1. 概述
2.对象
- 引用计数法
- 难以解决对象之间互相循环引用的问题
- 可达性分析算法
- 当一个对象
- 到GC没有任何引用链,此对象不可用
- 引用
- 强引用、软引用、弱引用、虚引用
- 生存还是死亡
- 如果对象在可达性分析后被发现不可达,它会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法
- 若有必要,这个对象则会被放到F-Queue中缓慢执行
- 在执行finalize()是最后一次逃脱被销毁的机会——将自己与另一个引用链上的对象建立引用
- finalize()只会被执行一次
- 回收方法区
3. 垃圾回收算法
- 标记-清除算法
- 首先标记出要回收的对象,在标记完成后统一回收所有被标记的对象
- 效率不高,标记和清除都比较慢
- 空间问题,标记清除会产生大量不连续的内存碎片,分配大对象内存时,如果没有足够内存会再次触发垃圾收集
- 复制算法
- 将可用内存分为大小相等两块,当其中一块内存用完了,就把还活着的对象复制到另一块上,再将这一块一次清理完
- 减小一半可用内存,代价太大
- 不需要1:1划分空间
- 标记-整理算法
- 复制算法在存活率高的时候效率比较低
- 标记后使其向一边移动,然后直接清理边界内存
- 分代收集算法
- 把内存按照对象存活周期分为几个部分,根据各个年代采用最适当的算法
4. HotSpot算法实现
- 枚举根节点
- 查找全局引用和暂停来保证一致性上会耗费很多时间
- 安全点
- 程序不能再任意位置停下来进行GC,于是设置适当的安全点
- 抢先式中断:首先把线程全部暂停,如果发现有线程不在安全点上,就恢复它让它跑到安全点上
- 主动式中断:不对线程进行操作,设置一个标志,各个线程执行时主动轮询这个标志,发现中断标志为真就暂停
- 安全区域
- 为正在休眠的线程设计
5. 垃圾收集器
- Serial收集器
- 单线程、“stop the world”
- 没有线程交互开销,专心做垃圾收集自然可以获得最高的单线程收集效率
- ParNew收集器
- Serial的多线程版
- Parallel Scavenge收集器
- 目标是达到一个可控制的吞吐量,更高效利用CPU
- Serial Old收集器
- Serial收集器的老年代版
- Parallel Old收集器
- Parallel Scavenge老年版
- CMS收集器
- 以最短停顿时间为目标的收集器
- 基于“标记-清除”实现
- CMS收集器的内存回收过程和用户线程一起并发执行
- 并发收集、低停顿
- 对CPU资源非常敏感
- 无法处理浮动垃圾
- GI收集器
- 并行与并发
- 分代收集
- 空间整合
- 可预测停顿
- GC日志
6. 内存分配与回收策略
- 对象优先在eden分配
- 大对象直接进入老年代
- 长期存活的对象将进入老年代
- 动态对象年龄判断
- 空间分配担保