【JVM】一、运行时数据区域
一、线程私有
1. 程序计数器
执行java方法时,记录的是正在执行的字节码指令的地址。
执行native本地方法时,值为空。
2. Java 虚拟机栈
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、常量池引用、操作数栈等信息。每个方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
该区域可能抛出以下异常:
- 当线程请求的栈深度超过最大值,会抛出
StackOverflowError异常; - 栈进行动态扩展时如果无法申请到足够内存,会抛出
OutOfMemoryError异常。
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小。
java -Xss 2M HackTheJava在 JDK 1.4 中默认为 256K,而在 JDK 1.5+ 默认为 1M。
3. 本地方法栈
与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。
本地方法是指用其它语言编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
JNI(Java Native Interface)提供了若干API,来支持Java和本地代码间的双向交互。
二、非线程私有
1. 堆
所有对象都在这里分配内存。
是垃圾收集的主要区域。现代的垃圾收集器基本都是采用分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回收算法。因此可以将堆分成两块: 新生代和老年代。
堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。
可以通过 -Xms 和 -Xmx 这两个虚拟机参数来指定一个程序的堆内存大小,第一个参数设置初始值,第二个参数设置最大值。
默认空余堆内存小于 40% 时,JVM 就会增大堆直到 -Xmx 的最大限制;空余堆内存大于 70% 时,JVM 会减少堆直到 -Xms 的最小限制;服务器一般设置-Xms、-Xmx 相等以避免在每次 GC 后调整堆的大小。
java -Xms 1M -Xmx 2M HackTheJava
2. 方法区
用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
和堆一样不需要连续的内存,并且可以动态扩展,动态扩展失败一样会抛出 OutOfMemoryError 异常。
对这块区域进行垃圾回收的主要目标是对常量池的回收和对类的卸载,但是一般比较难实现。
方法区是一个 JVM 规范,永久代与元空间都是其一种实现方式。元空间位于本地内存中,而不是虚拟机内存中。
从 JDK 1.8 开始,移除永久代,开始采用元空间。原来永久代的数据被分到了堆和元空间中。其中,静态变量和常量池等放入堆中,类的元信息被放入元空间中。
3. 运行时常量池
方法区的一部分。
Class 文件中的常量池(编译器生成的字面量和符号引用)会在类加载后被放入这个区域。一般翻译出来的直接引用也会放入这个区域。
除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()。

浙公网安备 33010602011771号