本章目标:
- 了解HotSpot的基本架构
- 了解HotSpot的主要组件
- 了解HotSpot的自动化策略
VM运行时环境,JIT编译器,内存管理器是本章的重点。
3.1 HotSpot VM 的基本架构
HotSpot VM 的基本架构
- 垃圾收集器(自动内存管理):用于收集Java堆和方法区中对象使用的内存。
- JIT编译器:JIT 是 just in time 的缩写, 也就是即时编译编译器。使用即时编译器技术,能够加速 Java 程序的执行速度.
- HotSpot VM运行时职责:命令行解析、VM生命周期管理、类加载、字节码解释、异常处理、同步、线程管理、Java本地接口、VM致命错误处理、非Java堆管理
普通对象指针(Ordinary Object Pointers oops):指向对象的引用
压缩指针(Compressed oops):Java虚拟机利用对齐/偏移量等算法将64位指针压缩陈32位。Jvm开启此功能的命令行参数时:-XX:UseCompressedOops, jdk1.6 u23 之后默认开启
复习Java虚拟机规范内容
运行时数据区域
Java 虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机
启动而创建,随着虚拟机退出而销毁。另外一些则是与线程一一对应的,这些与线程对应的数据区
域会随着线程开始和结束而创建和销毁。
线程公有区域
- Java堆
- 多线程共享
- 虚拟机启动时创建
- 存储各种对象,对象由GC管理
- 不要求内存连续
- 用户可以调整其大小,调整参数:
- 方法区
- 多线程共享
- 存储类的结构,例如运行时常量池(Runtime Constant Pool)、属性和方法数据、构造函数和普通方法的字节码内容、还包括一些在类、实例、接口初始化时用到的特殊方法
- 虚拟机启动时创建
- 可以进行垃圾收集或不收集
- 内存不要求连续
- 用户可以调整其大小,调整参数:
- 如果方法区的内存空间不能满足内存分配请求,那 Java 虚拟机将抛出一个OutOfMemoryError 异常。
线程私有区域
- 程序计数器(PC寄存器)
- 线程私有
- 存储 Java 虚拟机正在执行的字节码指令的地址
- 如果该方法是 native 的,那 PC 寄存器的值是 undefined
- PC 寄存器的容量至少应当能保存一个 returnAddress 类型的数据或者一个与平台相关的本地指针的值
在任意时刻,一个 Java 虚拟机线程只会执行一个方法的代码,这个正在被线程执行的方法称为该线程的当前方法(Current Method)
- Java 虚拟机栈
- 线程私有空间
- 线程创建时创建
- 存储栈帧/局部变量和一些过程结果
- 不需要保证内存连续
- 用户可以调整其大小或固定大小,调整参数:
注:因为除了栈帧的出栈和入栈之外,Java 虚拟机栈不会再受其他因素的影响,所以栈帧可以在堆中分配
Java 虚拟机栈可能发生如下异常情况:
- 如果线程请求分配的栈容量超过 Java 虚拟机栈允许的最大容量时,Java 虚拟机将会抛出一个 StackOverflowError 异常。
- 如果 Java 虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是目前无法申请到足够的内存去完成扩展,或者在建立新的线程时没有足够的内存去创建对应的虚拟机栈,那 Java 虚拟机将会抛出一个 OutOfMemoryError 异常。
- 本地方法栈
- 线程私有
- 并非所有的虚拟机都需要实现,不支持本地方法时可以不实现
- 线程创建时创建
- 可以固定大小或动态扩展,允许用户调整其大小
异常情况
- 如果线程请求分配的栈容量超过本地方法栈允许的最大容量时,Java 虚拟机将会抛出一个StackOverflowError 异常。
- 如果本地方法栈可以动态扩展,并且扩展的动作已经尝试过,但是目前无法申请到足够的内存去完成扩展,或者在建立新的线程时没有足够的内存去创建对应的本地方法栈,那 Java 虚拟机将会抛出一个 OutOfMemoryError 异常。
参考资料
https://docs.oracle.com/javase/specs/index.html
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html
https://www.ibm.com/developerworks/cn/java/j-lo-just-in-time/