程序计数器
记录正在执⾏的虚拟机字节码指令的地址(如果正在执⾏的是本地⽅法则为空)。
Java 虚拟机栈
每个 Java ⽅法在执⾏的同时会创建⼀个栈帧⽤于存储局部变量表、操作数栈、常量池引⽤等信息。从 ⽅法调⽤直⾄执⾏完成的过程,对应着⼀个栈帧在 Java 虚拟机栈中⼊栈和出栈的过程。
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存⼤⼩,在 JDK 1.4 中默认为 256K,⽽在 JDK 1.5+ 默认为 1M:
该区域可能抛出以下异常: 当线程请求的栈深度超过最⼤值,会抛出 *Error 异常; 栈进⾏动态扩展时如果⽆法申请到⾜够内存,会抛出 OutOfMemoryError 异常。
本地⽅法栈
本地⽅法栈与 Java 虚拟机栈类似,它们之间的区别只不过是本地⽅法栈为本地⽅法服务。 本地⽅法⼀般是⽤其它语⾔(C、C++ 或汇编语⾔等)编写的,并且被编译为基于本机硬件和操作系统 的程序,对待这些⽅法需要特别处理。
所有对象都在这⾥分配内存,是垃圾收集的主要区域("GC 堆")。 现代的垃圾收集器基本都是采⽤分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回 收算法。
可以将堆分成两块:新⽣代(Young Generation) ⽼年代(Old Generation)
堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。 可以通过 -Xms 和 -Xmx 这两个虚拟机参数来指定⼀个程序的堆内存⼤⼩,
第⼀个参数设置初始值,第 ⼆个参数设置最⼤值。
⽅法区
⽤于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 和堆⼀样不需要连续的内存,并且可以动态扩展,动态扩展失败⼀样会抛出 OutOfMemoryError 异常。
对这块区域进⾏垃圾回收的主要⽬标是对常量池的回收和对类的卸载,但是⼀般⽐较难实现。 HotSpot 虚拟机把它当成永久代来进⾏垃圾回收。但很难确定永久代的⼤⼩,因为它受到很
多因素影 响,并且每次 Full GC 之后永久代的⼤⼩都会改变,所以经常会抛出 OutOfMemoryError 异常。为了更 容易管理⽅法区,从 JDK 1.8 开始,移除永久代,并把⽅法区移⾄元空间,
它位于本地内存中,⽽不是虚拟机内存中。 ⽅法区是⼀个 JVM 规范,永久代与元空间都是其⼀种实现⽅式。在 JDK 1.8 之后,原来永久代的数据 被分到了堆和元空间中。元空间存储类
的元信息,静态变量和常量池等放⼊堆中。
运⾏时常量池
运⾏时常量池是⽅法区的⼀部分。 Class ⽂件中的常量池(编译器⽣成的字⾯量和符号引⽤)会在类加载后被放⼊这个区域。 除了在编译期⽣成的常量,还允许动态⽣成,
例如 String 类的 intern()。
直接内存
在 JDK 1.4 中新引⼊了 NIO 类,它可以使⽤ Native 函数库直接分配堆外内存,然后通过 Java 堆⾥的 DirectByteBuffer 对象作为这块内存的引⽤进⾏操作。这样能在⼀些场景中显著提⾼性能,因为避免了 在堆内存和堆外内存来回拷⻉数据。