说说常见的垃圾回收算法
-
标记-清除算法
- 标记:Collector从引用根节点开始遍历,标记所有引用的对象。一般是在对象的header中记录为可达对象。
- 清除:Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则对其回收。
缺点
-
效率不高,标记和清除2个阶段效率都不高;
-
这种方式清理出来的空闲内存是不连续的,产生内存碎片。需要维护一个空闲列表
-
在进行GC的时候,需要停止整个应用程序,导致用户体验差
-
复制算法
- 核心思想:将活着的内存空间分为2块,每次只使用其中的一块,在垃圾回收时将正在使用的内存中存活对象复制到未被使用的内存块中,之后清除正在使用的内存块中的所有对象,交换2个内存的角色,最后完成垃圾回收
-
优点:
- 没有标记和清除过程,实现简单,运行高效
- 复制过去以后保证空间的连续性,不会出现碎片问题。
-
缺点:
- 此算法的缺点也很明显,就是需要2倍的内存空间
- 对于G1这种分拆为大量的region的GC,复制而不是移动,意味着GC需要维护region之间对象引用关系,不管是内存占用或者时间开销也不小。
-
注意:
- 如果系统中的垃圾对象很多,复制算法需要复制的存活对象数量并不会太大,效率非常低。
-
应用场景:新生代的幸存者区。
-
标记压缩:
-
执行过程:
- 第一阶段:和清除算法一样,从根节点开始标记所有被引用对象
- 第二阶段:将所有的存活对象压缩在内存的一端,按顺序排放
- 最后:清理边界外所有的空间。
- 相比清除回收算法,它是非移动式的回收算法,或者手是移动式的。
-
优点:
- 清除了清除算法中,内存区域分散的缺点, 我们需给对象分配内存时,JVM只需要持有一个内存的起始地址即可。
- 消除了复制算法当中,内存减半的高额代价。
-
缺点:
- 从效率上来说,标记整理算法要低于复制算法。
- 移动对象的同时,如果对象被其他对象引用,则还需要调整引用的地址。
- 移动的过程中,需要全程暂停用户应用程序。
-
-
分代收集算法
- 概念:目前所有的GC都是采用的分代收集算法执行垃圾回收的。
- 年轻代:(复制算法)
- 区域相比老年代较小,对象生命周期短,存活率低,回收频繁。
- 老年代:(标记清除或者标记整理)
- 区域较大,对象生命周期长,存活率高,回收不及年轻代频繁。