GC算法

  • 空间维度上:标记-清除、标记-压缩(老生带)、标记-复制(新生代)、增量回收、分代回收
  • 时间维度上:串行回收、并行回收、并发回收

空间维度的算法分类

标记-清除

标记清除的算法最简单

  • 主要是标记出来需要回收的对象,然后把这些对象在内存的信息清除
  • 会产生大量内存碎片

标记清除

标记-压缩(常见于老年代)

这个算法是在标记-清除的算法之上进行剪切操作,将存活对象压缩在一起,减少内存碎片

  • 由于压缩空间需要一定的时间,会影响垃圾收集的时间

标记压缩

标记-复制(常见于新生代)

这个算法是把内存分配为两个空间,一个空间(A)用来负责装载正常的对象信息,另外一个内存空间(B)是垃圾回收用的。

  • 每次把空间A中存活的对象全部复制到空间B里面,在一次性的把空间A删除。
  • 这个算法在效率上比标记-清除-压缩高,但是需要两块空间,对内存要求比较大,内存的利用率比较低
  • 适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。
  • 一般而言,内存分为一块较大的Eden与两个较小的Survivor(8:1:1)

标记复制

增量回收

  • 把堆分为多个域,每次对从一个域进行垃圾回收
  • 这样只会造成一小部分程序暂停

分代回收:(JVM采取的算法)

  • 基于对对象生命周期分析后得出的垃圾回收算法
  • 把对象分为新生代、老生代,对不同生命周期的对象使用不同的算法进行回收

按生命周期分类

时间维度的算法分类

串行回收

  • 用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高
  • 无法使用多处理器的优势,所以此收集器适合单处理器机器

串行回收

并行回收

是多线程处理所有垃圾回收工作,可以利用多核处理器的优势

  • 对于空间不大的区域(如young generation),采用并行收集器停顿时间很短,回收效率高,适合高频率执行
  • 如果线程数量过多,导致线程之间频繁调度,也会影响性能
  • 一般并行收集的线程数是处理器的个数

并行回收

并发回收

并发时GC线程和应用线程大部分时间是并发执行,只是在初始标记(initial mark)和二次标记(remark)时需要stop-the-world,这可以大大缩短停顿时间(pause time),所以适用于响应时间优先的应用,减少用户等待时间。

  • 由于GC是和应用线程并发执行,只有在多CPU场景下才能发挥其价值,在一个N个处理器的系统上,并发收集部分使用K/N个可用处理器进行回收,一般情况下1<=K<=N/4
  • 在执行过程中还会产生新的垃圾floating garbage(浮动垃圾),如果等空间满了再开始GC,那这些新产生的垃圾就没地方放了(并发收集器一般需要20%的预留空间用于这些浮动垃圾),这时就会启动一次串行GC,等待时间将会很长,所以要在空间还未满时就要启动GC
  • mark和sweep操作会引起很多碎片,所以间隔一段时间需要整理整个空间,否则遇到大对象,没有连续空间也会启动一次串行GC
  • 用此收集器,收集频率不能大,否则会影响到cpu的利用率,进而影响吞吐量

并发回收