对象内存布局:
对象头
实例数据
对齐填充
对象头:
Mark Word:存储自身的运行时数据,如hashcode,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳
类型指针,指向其类元数据的指针,虚拟机根据该指针判断对象类型
各种类型字段的顺序受一下两个因素的影响:
虚拟机分配策略参数(FieldsAllocationStyle)
源码中字段定义顺序
HotSpot VM的自动内存管理系统要求对象地址必须是8字节的整数倍,即对象的大小必须是8字节的整数倍,对象头正好是8字节的倍数,因此当对象实例数据部分没有对齐时,需要通过padding来对齐
引用计数算法很难解决对象之间的相互循环引用的问题。
可作为GC Roots的对象:
虚拟机栈中引用的对象
方法区中类静态属性引用的对象
方法去中常量引用的对象
本地方法栈中JNI引用的对象
Java中最初的引用定义:如果reference类型的数据中存储的数值代表的是一个内存地址,则该内存代表者一个引用。
Java引用的扩充:
强引用:代码中通过变量显式声明的对象
软引用(SoftReference):在系统将要发生内存溢出异常前,会把这类对象列入回收范围,进行第二次回收。即:分配内存—>内存不足->第一次垃圾收集->内存不足->第二次垃圾收集(回收软引用对象)->内存不足异常/分配成功
弱引用(WeakReference):弱引用关联的对象只能生存到下一次垃圾回收发生之前,当垃圾回收器工作时,都会默认回收掉该类型的对象
虚引用(PhantomReference):设置虚引用的唯一目的是能在这个对象被回收掉时收到一个系统通知。
任何对象在被回收前至少经历两次标记过程,在进行可达性分析后,如果法相某对象没有与GC Roots相连,它将会第一次被标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。如果该对象没有覆盖finalize方法或该对象的finalize方法已经被调用过一次了,虚拟机都被认为没有必要执行。finalize方法是对象逃脱被回收的最后也是唯一一次机会,即覆盖finalize方法,并在实现中重新使自己被某个变量引用上。
垃圾收集算法:
标记-清除(Mark-sweep):
标记和清除两个过程效率都不高
产生内存碎片
复制(Copying):
内存利用率低
标记-整理(Mark-Compact)
垃圾收集器
Serial 收集器 单线程,stop-the-world
ParNew 收集器 Serial的并行版本,只有ParNew能与CMS收集器配合实用
Parallel Scavenge收集器 目标是达到一个可控制的吞吐量(用户代码运行时间/总运行时间),也叫吞吐量优先收集器
Serial Old收集器 与Parallel Scavenge配合使用;作为CMS的后备方案
Parallel Old收集器 Parallel Scavenge的老年代版本,使用多线程的标记-整理算法
CMS(Concurrent Mark Sweep) 并发收集,停顿低。 缺点: 1. 对CPU非常敏感 2. 无法处理浮动垃圾 3. 内存碎片
G1
内存分配与回收策略
对象优先在Eden区分配
大对象直接进入老年代
长期存活的对象将进入老年代
空间分配担保
[x] 待完成