所有的学习都需要基于原理,理解了原理才是最高效的!
理解JVM的内存,可以从理解代码在是如何在虚拟机中执行的,代码是如何存储在虚拟机?一个类、方法及其实例是怎么存储的?OutOfMemory和StackOverflow是怎么出现的?带着这些问题去阅读JVM的相关文章会事半功倍,加深理解。本文也不例外!
在看本文之前,需要先告知:
虚拟机是基于栈去执行指令的!
一、虚拟机内存区域概貌
在学习新生代老年代(稍后会讲到)之前,先来了解一下jvm的内存概貌,有个全貌的认识。Java内存区域如下图划分:
1、程序计数器
程序计数器,存储虚拟机下一条执行指令的地址引用,线程私有。
2、虚拟机栈
虚拟机栈,由栈帧组成,每个栈帧是一个方法,栈顶的栈帧即为当前执行的方法。每一条指令的执行都是栈帧入栈和出栈的过程,线程私有。
3、本地方法栈
本地方法栈存储Java Native方法服务,线程私有。
4、方法区
方法区,编译后的代码存储于此,还有方法参数、局部变量表、常量池等。
5、堆
堆,主要的垃圾回收区域,存储实例对象。
二、Java方法执行过程
Java方法执行过程是基于栈结构实现的,主要过程如下:
1、程序计数器记录了下一条指令的地址。
2、虚拟机栈拿到地址后会从方法区加载代码、方法参数和局部变量表(首次执行方法),伴随着入栈和出栈的过程执行指令,执行过程中还需要引用常量池。
3、指令执行过程中,有实例化的对象,会存储到堆中,栈帧存储的则为引用。
4、指令执行过程中,需要调用native本地方法(如current包涉及cas的操作需要Unsafe的cas相关方法去支撑)则会调用本地方法栈。
常见问题1:什么情况会出现StackOverflowError的错误?
答:这类型错误一般出现在栈帧,因为栈是有深度限制的,一旦超过了深度,比如一直在递归自己,则会导致栈溢出,也就是StackOverflowError。
常见问题2:什么情况会出现OutOfMemoryError的错误?
答:这类型错误一般出现在堆,当不断的有对象实例化后未被垃圾回收器回收的实例空间大于现有的堆空间,则会报错。