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的利用率,进而影响吞吐量