JVM运行时数据区域(Java Virtual Machine Run-Time Data Areas)
Java虚拟机在运行程序期间会划分运行时数据区域,有些数据区域随着jvm的启动而创建,退出而销毁。有些数据区域随着线程的启动和结束而创建和销毁。
这里放一张我盗来的图,图来源文章链接在文末;
从上图可以看出来、PC Register、JVM Stack、Native Method Stack 是线程私有的数据区域,而Heap ,Method Area是共有的数据区域。下面我们来详细了解下各个数据区域。
PC(Program Counter) Register 程序计数寄存器
在深入理解Java虚拟机一书中,pc register翻译为程序计数器;个人翻译为程序计数寄存器 (我喜欢,任性)。
jvm可以支持多个线程并发执行,每个线程都有自己独立的pc register,在某一时刻,某个java线程正在执行的某个方法,如果这个方法是native方法,计数器的值为空(undefined),如果这个方法不是native方法,计数器的值为正在执行的虚拟机字节码指令的地址。
JVM Stacks Java虚拟机栈
从图中可以看出,每个线程都有自己独立的栈,随着线程的创建而创建,结束而销毁。
一个栈中存储了帧(frames),帧里面存了局部变量表、操作数栈、动态链接、方法出口等信息。
下面是我盗来的另一张图,很形象的描述了栈和帧的关系。(文末放传送门)
在这个区域,有两种异常状况:
- StackOverflowError
如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出该异常。 - OutOfMemoryError
如果虚拟机栈可以动态扩展(当前大部分JVM都可以动态扩展),如果扩展时无法申请到足够的内存,将会抛出该异常.
Native Method Stacks 本地方法栈
本地方法栈与虚拟机栈作用类似,他们的区别不过是,虚拟机栈为Java方法服务,而本地方法栈为native方法服务,与虚拟机栈一样,本地方法栈也会抛出StackOverflowError与OutOfMemoryError 异常。
Heap 堆
看最上面那个图就知道,Heap是被所有线程所共享的一块数据区域。该数据区域随着JVM启动时而创建,该数据区域存储了所有的对象(Class Instance)和数组。Heap是垃圾收集器管理的主要区域,所以别名GC堆(Garbage Collector Heap(叫垃圾堆好像也没啥毛病))。
根据Java 虚拟机规范的规定,Java Heap 可以处在物理上不连续的内存空间中,只要逻辑上是连续的即可。
该区域可能抛出异常:
- OutOfMemoryError.
当堆中内存不足以分配给新创建的对象时,就会抛出该异常.
Method Area 方法区 (别名Non-Heap 非堆)
和堆一样,方法区也是被所有线程所共享的内存区域,方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
该区域可能抛出异常:
- OutOfMemoryError.
当堆中内存不足以分配给新创建的对象时,就会抛出该异常.
Run-Time Constant Pool 运行时常量池
运行时常量池是每个类或每个接口运行时类文件中的constant_pool表的表现形式。
每个运行时常量池由JVM方法区分配内存。
该区域可能抛出异常:
- OutOfMemoryError.
When creating a class or interface, if the construction of the run-time constant pool requires more memory than can be made available in the method area of the Java Virtual Machine, the Java Virtual Machine throws an OutOfMemoryError.
参考资料
- https://blog.seveniu.com/post/the-jvm-run-time-data-areas/
- Java虚拟机的内存组成以及堆内存介绍
- https://mritd.me/2016/03/22/Java-%E5%86%85%E5%AD%98%E4%B9%8B%E6%96%B9%E6%B3%95%E5%8C%BA%E5%92%8C%E8%BF%90%E8%A1%8C%E6%97%B6%E5%B8%B8%E9%87%8F%E6%B1%A0/
- https://alvinalexander.com/scala/fp-book/recursion-jvm-stacks-stack-frames
- 深入理解Java虚拟机