一图顶千言
1.1 程序计数器
“程序计数器”是虚拟机中一块较小的内存空间,主要用于记录当前线程执行的位置。
1.2 虚拟机栈
1.2.1栈帧
栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,每一个线程在执行某个方法时,都会为这个方法创建一个栈帧。
我们可以这样理解:一个线程包含多个栈帧,而每个栈帧内部包含**局部变量表、操作数栈、动态连接、返回地址等。 **
局部变量表:顾名思义保存局部变量.
操作数栈:在方法执行的过程中,会有各种字节码指令被压入和弹出操作数栈
动态链接:因为一个方法要调用其他方法,需要将这些方法的符号引用转化为其所在内存地址中的直接引用,而符号引用存在于方法区中。
返回地址:用来帮助当前方法恢复它的上层方法执行状态。
1.3 本地方法栈
本地方法栈和上面介绍的虚拟栈基本相同,只不过是针对本地(native)方法。在开发中如果涉及 JNI 可能接触本地方法栈多一些,在有些虚拟机的实现中已经将两个合二为一了(比如HotSpot)。
1.4 堆
Java 堆(Heap)是 JVM 所管理的内存中最大的一块,该区域唯一目的就是存放对象实例,几乎所有对象的实例都在堆里面分配
1.5 方法区
1.6 StackOverflowError
当线程请求栈深度超出虚拟机栈所允许的深度时抛出。
1.7 OutOfMemoryError
当 Java 虚拟机动态扩展到无法申请足够内存时抛出。
总结
对于 JVM 运行时内存布局,我们需要始终记住一点:上面介绍的这 5 块内容都是在 Java 虚拟机规范中定义的规则,这些规则只是描述了各个区域是负责做什么事情、存储什么样的数据、如何处理异常、是否允许线程间共享等。千万不要将它们理解为虚拟机的“具体实现”,虚拟机的具体实现有很多,比如 Sun 公司的 HotSpot、JRocket、IBM J9、以及我们非常熟悉的 Android Dalvik 和 ART 等。这些具体实现在符合上面 5 种运行时数据区的前提下,又各自有不同的实现方式。
本文内容总结自拉勾教育姜新星老师的Android工程师进阶课程