参考 《深入理解Java虚拟机 JVM高级特性与最佳实践》2.2节
1.线程相关区域
1.1 程序计数器
- 所谓程序计数器就是存储下一条指令地址的一个地方。
- 因为线程之间切换的话本质上是一个cpu不停地在来回切,所以要对每个线程保留它自己当前执行到哪里的位置,也就是程序计数器是线程相关的原因。
- 如果当前执行的是Java方法,则计数器里放的是当前字节码的地址;如果执行的是native方法,则为undefined(空)。
- 此区域是JVM唯一一个没有定义OutOfMemoryError情况的区域。估计也是因为这块根本就没有内存增长的需求吧。
1.2 Java虚拟机栈
- 栈其实就是方法调用的模型,虚拟机栈就是用在方法调用上的。仔细想想的话方法调用过程就是压栈出栈的过程。
- 开始执行一个方法的时候,创建一个栈帧,这个栈帧会被压入栈(所以就是栈的一帧),一个栈帧包含了局部变量表,操作数栈,动态链接,方法出口信息等,方法执行完了就出栈。
- 编译期间可以确定局部变量表所需的空间。在编译期就确定就省得运行时再去计算了需要分配的大小了。
- 除了long和double需要两个局部变量空间外,其他的都只需要1个变量空间(slot)。
- 这个区域定义了两种异常状况:如果线程请求的栈深度大于虚拟机允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展的话,无法再申请到足够的内存时,会抛出OutOfMemoryError。(?那是先抛出OutOfMemoryError还是StackOverflowError呢)
1.3 本地方法栈
本地方法栈和Java虚拟机栈的功能是一样的,只不过服务的对象不一样。本地方法栈是为本地方法服务的,Java虚拟机栈是为Java方法服务的。其他的没有什么区别。像Hotspot甚至把本地方法栈和虚拟机栈做在一起了。
2.线程无关区域
2.1 堆
堆是存放对象的地方,具体讨论在第三章
2.2 方法区
- 方法区存放的是类信息,常量,静态变量,即时编译器(JIT?)编译后的代码等数据。
- 当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。
- 运行时常量池是方法区的一部分
3.直接内存
- 直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。
-
主要的一个用法就是用native函数申请内存,然后Java和native函数之间就不用再相互复制数据而是直接去这个直接内存去取数据了。