JVM内存模型
程序计数器
- 线程私有,当前线程锁执行的字节码的行号指示器
- 无OutOfMemory错误
虚拟机栈
- 线程私有,Java方法执行时会创建栈帧,存储 局部变量表,操作数栈,动态链接和方法出口等信息
- 局部变量表存放各种编译器可知的基本数据类型boolean、byte、char、short、int、float、long、double、对象引用(地址)和returnAddress(下一条字节码指令地址)
- 局部变量表的内存空间在编译器分配完成,方法运行期间不会改变其大小。
本地方法栈
- 虚拟机使用本地Native方法服务
- 有的虚拟机把这部分与虚拟机栈合并
Java堆
- 线程共享,存放对象实例,几乎所有的对象实例以及数组都要在堆上分配
- 垃圾回收的主要区域,GC堆
- 可以处在物理不连续的空间上,但是逻辑上要连续
方法区(也叫堆-永久代)
线程共享,存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码
运行时常量池:存放编译器生成的各种字面量和符号引用
Java对象创建
常量池检查
遇到一条New指令后,先去常量池检查这个类是否已经被加载,如果没有,则执行类加载
类加载
内存分配
对象所需内存的大小在类加载后就可以完全确定(通过类元数据信息),然后将同等大小的内存从堆中划分给对象。
分配方法:
- 规整内存:指针碰撞
- 不规整内存:空闲列表
分配同步:
- CAS+失败重试
- 本地线程分配缓冲
设置对象头
对象内存 = 对象头 + 实例数据 + 对齐填充
对象头一般包括两部分信息:
- 存储对象自身的运行时数据(hashCode,GC Age, 锁状态等) 一个字长大小,也叫“MarkWord”,非固定结构,根据对象的不同状态,存储不同含义的数据
- 类型指针,对象指向类元数据的指针。如果是数组,还需要记录数组长度
实例数据:类中所定义的各种类型的字段内容
对齐填充:HotSpot要求对象起始地址必须是8字节的整数倍,对象的大小必须是8字节的整数倍。
访问对象
通过操作栈上的Reference数据来操作堆上的对象,如何实现Reference:
- 句柄:二层索引,稳定
- 指针:一层索引,快速高效
垃圾收集
程序计数器和虚拟机栈、本地方法栈随线程生存消亡,内存分配回收相对确定,但是堆上内存就复杂的多,需要设计垃圾回收算法进行回收。
如何判断哪些对象需要被回收
- 引用计数:无法解决循环引用
- 可达性分析:GCRoot无法到达该对象,该对象就标为死亡
- 可以作为GCRoots的结点:栈上引用对象(局部变量),永久代上引用对象(静态变量和常量)
- 对象在可达性分析中不可达后,不代表一定会消亡,在标记过程中,会触发finalize方法(只会触发一次,没有实现该方法则不触发),如果对象重新与引用链关联上,就不会被回收。这里的触发只是JVM会调用该方法,但不一定等待该方法执行完
方法区回收
- 废弃常量
- 没有其他地方引用该常量
- 无用的类
- 该类所有实例都已被回收
- 加载该类的ClassLoader被回收
- 该类对应的java.lang.class对象没有在任何地方被引用
垃圾回收算法
标记-清除算法
- 标记所有需要清除的对象,然后再统一回收
- 存在效率问题和空间问题(内存碎片)
复制算法
- 内存对半分,用完一半,回收时,将存活对象复制到另外一半,顺序排列
- 简单高效,但是内存容量缩小
- 一个大的Eden空间和两个小的survivor空间,每次使用Eden和一个survivor(from),在回收时,将其中还存活的对象一次性复制到另外一个survivor(to)中,当survivor(to)空间不够时,依赖其他内存进行分配担保
标记-整理算法
- 标记需要清理的对象,然后存货对象向内存一端移动
分代收集算法
- Java堆划分为新生代和老年代,新生代存储新分配的对象,老年代存放存活周期大和内存空间大的对象
- 新生代对象代谢频繁,使用复制算法,老年代存活率高,使用另外两种算法。
内存分配回收策略
- 对象优先分配在Eden
- 对象将尝试在Eden中分配,如果空间不够,则调用一次MinorGC
- MinorGC 发生在新生代,很快; MajorGC FullGC 发生在老年代,比较慢
- 大对象直接进入老年代
- eg.长字符串和数组
- 长期存活的对象将进入老年代
- 对象年龄AGE:每在Survivor区中熬过一次MinorGC就长一岁,默认15岁就要去老年代
- 动态年龄对象判定:如果在survivor空间中相同年龄的对象大小的总和大于survivor空间的一半,则年龄大于或等于该年龄的就可以直接进入老年代
- 空间分配担保
- 老年代为新生代MinorGC提供担保
- 在复制算法中,如果survivor(to)空间不足,则将剩余的存活对象装入老年代中。