垃圾回收算法
- 标记-清除(Mark-Sweep)
- 标记需要回收的对象,清除所有回收对象的内存区域
- 标记与清除过程的效率不高
- 会产生大量不连续的内存碎片,不利于分配大对象(无足够的连续内存时,会触发另一次垃圾收集)。
- 停止-复制
- 将可用内存等分为两块。每次仅使用一块,当内存耗尽,将活着的对象规整地放入另外一块内存。
- 内存区域规整,分配内存仅需移动指针即可。
- 缺点:浪费一半内存。
- 标记-整理(Mark-Compact)
- 标记需要回收的对象,将存活对象往内存的一端移动,然后清除边界外的内存
- 分代收集
- 新生代的对象大部分是“朝生夕死”,只有少量存活,使用“复制”算法
- 老年代由于对象存活率高,且没有分配担保,使用标记-清除或标记-整理
- HotSpot算法实现
- 枚举根节点
- GCRoots时,存在检查内存所有区域过于耗时和需要STW保证一致性。
- 因此必须保证准确式GC,直接得知对象引用存在哪。
- OopMap,在类加载完成时,将对象内什么偏移量上是什么数据类型计算出来,并且在JIT即时编译中,也会在特定位置记录栈和寄存器中哪些位置是引用。
- 安全点
- 安全点选择
- 不会为每条指令都生成OopMap,只在上述的特特定位置记录,即安全点
- 程序执行只有到达安全点才停顿下来进行GC。
- 因此安全点的选择以“是否具有让程序长时间执行的特征”为标准,一般是指令序列复用,比如方法调用、循环跳转、异常跳转等
- 如何保证GC时所有线程都到达最近的安全点停顿
- 抢先式中断(Preemptive Suspension)
- 不使用
- 中断所有线程。检查若有线程未到达安全点,则恢复线程,让其运行至安全点。
- 主动式中断(Voluntary Suspension)
- 设置中断标志,由其他线程主动轮询。当发现中断标志为真,则自行中断。
- 轮询时机与安全点是重合的,另外创建对象时需要分配内存的地方。
- 当需要暂停线程时,虚拟机将某个偏移量位置的内存页设置为不可读,当线程
- 抢先式中断(Preemptive Suspension)
- 安全点选择
- 安全区域
- 如何保证没有分配到时间片的线程响应GC中断
- 安全区域指在一段代码片段中,引用关系不会发生变化。
- 实现原理
- 当线程执行到安全区域的代码时,会标识自己进入。在此过程中,JVM发起GC,则不会理会标识进入安全区域的线程。
- 当线程离开安全区域时,会检查GC Roots(或者整个Gc过程)是否完成。
- 若完成则继续执行,否则等待收到可以离开安全区域的信号。
- 枚举根节点