JVM知识整中
根据书籍/教程/网络材料,整理一些JVM知识。
Java文件的生命
一个Java文件(Class文件)的使用生命周期为:加载 -> 连接 -> 初始化 -> 使用 -> 卸载。
其中 连接 阶段又可以详细为:验证 -> 准备 -> 解析 的过程。
即更加详细的过程为:加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载。
验证:版本校验(JDK版本可运行当前class文件),安全校验,元数据校验(Class文件本身的一些属性数据校验),字节码校验(是否符合Java的语法,如继承关系是否准确等)等。
准备:对类进行初始化,其中含有为类变量在方法区分配内存,并设置默认值。
static int a = 6; // 在准备阶段,JVM为变量a分配4个字节的内存空间,其默认值为0。
解析:将Class文件内的符号引用(没有歧义的描述符号)替换成直接引用(内存地址)。
类的初始化时机
类的初始化,并非实例对象的初始化。
- 创建实例(new 实例)。
- 引用类的静态变量,接口的变量。
- 反射类时,类被初始化。
- 调用类的静态方法。
- 初始化子类,其父类没有初始化的情况下,父类会被初始化。
- JVM启动时运行的类(包含main()方法的类)。
- 接口内声明有default方法的情况,在实现的子类初始化时,接口会被初始化。
不触发类的初始化/被动引用
- 子类引用父类的静态变量,不触发子类的初始化。
- 数组定义引用的类,不会触发初始化。
- 访问类的常量,不触发类的初始化。
堆的大小
- Xms: 初始堆大小,默认物理内存的1/64。
- Xmx: 最大堆大小,默认物理内存的1/4。
- Xms: 新生代大小,默认整个堆的3/8(37.5%,官方文档建议大小在 25%~50%,不建议修改)。
堆的部分指令
- -Xlog 打印log.
- 打印debug GC log. -Xlog:gc+heap=debug
- log输出到文件 -Xlog:gc+heap=debug:heapdump.log
- -Xms256m 设置初始堆大小256M。
- -Xmx1000m 设置最大堆大小1000M。
- -Xmn375m 设置新生代大小375M。
- -XX:+HeapDumpOnOutOfMemoryError OOM时导出堆到文件。
- -XX:HeapDumpPath 导出OOM的路径。
- -XX:NewRatio 设置老年代与新生代的比值。若已设置Xms==Xmx,且设置了Xmn,这个配置不需要设置。若配置-XX:NewRatio=2,表示老年内存代占比是新生代的2倍。
- -XX:SurvivorRatio 设置Eden区与Survivor区的比值。如设置-XX:SurvivorRatio=8,表示Eden区与一个Survivor去的比值是8,两个Survivor区与Eden区的比值就是2:8,即一个Survivor区占整个新生代内存区的1/10。
虚拟机栈
虚拟机栈也叫Java栈或帧栈。Java栈是线程私有的内存。Java栈内存储的帧,也叫栈帧。
栈帧:
- 支持JVM方法调用的数据结构。
- 栈帧会随着方法调用的开始而被创建,随方法调用结束而被销毁。
- 栈帧内存储了局部变量,动态链接,方法返回地址,操作数栈等。
局部变量表
局部变量表存放方法的参数,以及方法内定义的局部变量。用以存储的内存以slot为单位,每个slot是一个32位(4bytes)内存空间。
具体内容请跳转 Java栈——局部变量表
操作数栈
栈帧内操作数栈存储了JVM执行方法各指令的操作数。
具体内容请跳转 Java栈——操作数栈