垃圾标记算法
引用计数法: (每个对象都会有一个引用计数器,当该对象被引用一次之后,该计数器就会加一,当引用结束之后,计数器-1,当计数器为0的时候,就会被标记为垃圾回收对象)
优点:
实现简单,而且效率高。
缺点:
无法解决循环引用的问题。每个对象都需要单独的计数器来记录引用次数,占用空间。
根搜索算法:
以跟对象为起点,按照从上往下的顺序,判断链接对象是否可达。不可到达对象则被判定为垃圾对象,需要进行回收。
(并非说一旦不可达,就立马会被进行标记。至少要经历两次的标记过程。在执行gc回收的时候,会先去判断finalize函数,需要判断该对象是否有进行自救)
垃圾收集算法
标记清除法:
由于已经进行了相应的标记,那么在清除的时候也就会比较简单,只需要将被标记的对象保留,没有标记的对象进行回收即可。但是这个时候要注意,进行回收标记的时候,需要先暂停整个线程在进行标记。(原因自己可以思考一下)
对象被标记之前:
标记回收之后
缺点:
1.容易造成相应的碎片化空间。
2.需要进行暂停回收,而且还需要在堆里面进行递归遍历,性能不佳。
复制算法:
将内存分为了AB两块,(A正在使用的内存,B未使用的内存)将正在使用的对象复制到B内存中,然后对A进行垃圾回收。
内存区域中的对象会被分成两块
回收之后,只剩下存活对象的信息
缺点:
占用空间内存。需要复制,消耗性能。
标记压缩法
前期和标记清除算法一样,都是需要给相应的对象标记是否引用。但是后期则是将具有引用的对象往内存的一侧移动,进行整理,最后清理整理区域另一侧的对象。
缺点:
需要有额外的空间进行内存分配。
增量算法:
额外开一条线程,主程序在A线程执行,回收程序在B线程执行。B采用标记清除法和复制法的思路来分阶段性的进行回收,减少对于系统卡顿的影响。
缺点:
不断的进行AB线程之间的切换,会造成相应的系统性能消耗。
分代回收算法:
对于GC回收的分代如果了解的同学应该知道,大多数的对象存活周期都是比较短的。因此在进行垃圾回收的时候需要结合各个年代的对象特点来进行回收。
年轻代一般存活对象在第一次垃圾回收的时候就挂了,因此可以采用复制算法(会有额外的空间)
老年代中存活概率高,因此采用标记-整理算法。
关于垃圾回收器的分类
JVM在进行GC回收的时候,不同分代的内存会有不同类型的垃圾收集器来进行内存回收,不同的垃圾收集器有着自己的独有特点。垃圾收集器从并发的角度来分类主要分为两种类型:
一种是串行回收类型
另一种是并行回收类型
新生代的垃圾收集器
Serial 收集器
1.单线程模式的垃圾收集器
2.采用了复制算法来进行垃圾回收
3.对于机器性能不高的环境中,该垃圾收集器的工作效率较为有优势
ParNew 收集器
1.可以理解成多线程的Serial收集器,是一种多线程模式进行垃圾回收的收集器
2.在多核CPU环境中执行效率较高,但是在单核CPU环境里面执行的效率可能不如Serial收集器好
Parallel Scavenge收集器
1.采用了复制算法
2.相比于ParNew收集器,Parallel收集器更加关注于与吞吐量。(工作线程执行时间/(工作线程执行时间+GC停顿时间))
3.可以设置Stop the world机制的暂停时间值,让Parallel收集器在该限制收集器时间内完成垃圾回收。
这里需要注意到一点,在进行设置暂停时间值的时候,垃圾收集器本身的吞吐量和低延迟两个因素是相互矛盾的。因为如果吞吐量要求提高的话,那么每次延迟的时长就需要提升,相反当延迟时长缩短,那么每次进行垃圾回收时候的吞吐量也会降低。
老年代的垃圾收集器
Serial Old收集器
采用的是标记压缩算法,如果在单核cpu环境中,可以采用Serial 和Serial old收集器分别对年轻代和老年代的对象进行回收。
Parallel Old 收集器
Parallel收集器除了年轻代提供了Parallel Scavenge收集器以外,在老年代还提供了Parallel Old 收集器,采用的是多线程+标记压缩算法的方式来执行
CMS收集器
这是一款专门适用于对于系统低延迟做考虑的垃圾收集器,主要使用了标记清除算法。
CMS在进行垃圾回收的时候一共有四个步骤:
初始标记,并发标记,修改标记,并发回收
初始标记
初始标记的时候,需要从根节点开始进行搜索所有可达对象,进行标记,这个过程中会有一个叫做“stop the world”的情况发生。
并发标记
并发标记的过程中,主要是将之前不可达的对象进行标记,这个过程是不需要进行“stop the world” 操作的。
修改标记
由于之前在并发标记阶段没有进行stop the world处理,因此有可能部分标记的对象的不可达性不准确,所以这个阶段需要出发一次stop the world操作,进行相应标记校验和修改。
并发回收
这个阶段主要是对被标记的对象进行对象消除,释放内存空间。
综合各种垃圾收集器来说,我个人觉得单核cpu环境下使用serial收集器会比较合适,Parallel 收集器比较适用于吞吐量较大的环境中,cms收集器比较适合用于对于延迟性有要求的环境中。在了解清楚了各种垃圾收集器的特点之后,在实际项目开发中才能更加清楚的选择对应的优化方案。
最后附上一张关于垃圾收集器的总结脑图: