面试官:讲一讲有哪些垃圾收集算法?
回答:主要有三种:
1)标记-清除算法:这是最基础的算法,主要思想就是先标记出所有需要回收的对象,然后统一回收掉所有被标记的对象。 这个算法主要有两个缺点:
- 执行效率不稳定。如果堆中包含大量对象,而且其中大部分是需要被回收的,这时就必须进行大量的标记和清除的动作,也就是说执行效率和对象数量成反比
- 内存空间的碎片化问题。标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当程序运行过程中需要分配较大对象时,因无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作
后续两个算法 标记-复制算法 和 标记-整理算法 都是在 标记-清除算法 的基础上做的改进。
2)标记-复制算法:主要思想就是将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次性全部清理掉。 这个半区复制算法也有两个比较明显的问题:
- 不适用于对象存活率较高的情况(即一般不适用于老生代)
- 可用内存空间缩小了一半(针对这个问题,“Appel 式回收” 进行了改进,就是根据新生代 “朝生夕灭” 的特点,能够在一轮垃圾收集后活下来的对象少之又少,所以,我们其实并不需要这么大一块的保留区域。具体做法是把新生代分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次分配内存只使用 Eden 和其中一块 Survivor。发生垃圾收集时,在清空之前需要将存活对象复制到另一块 Survivor 中,然后直接清空 Eden 和已用过的那块 Survivor 空间。另外,使用 Apple 式回收的话,还需要有额外的空间进行分配担保,因为我们没有办法百分百保证分配给 To Survivor 的内存空间能够容纳全部的存活对象,常见的做法就是当 To Survivor 空间不足以容纳一次新生代 GC 之后存活的对象时,这些对象便将通过分配担保机制直接进入老年代)
- 标记-整理算法:主要思想就是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。这种移动式的算法相对于非移动式的标记-清除算法来说,吞吐量更高,不过速度相对较慢,因为移动对象需要 Stop the world。所以,
- 关注延迟/速度的收集器(比如 HotSpot 虚拟机中的 CMS 收集器)应该使用 Mark-Sweep 算法,
- 而关注吞吐量的收集器(比如 HotSpot 虚拟机中的 Parallel Old 收集器)应该使用 Mark-Compact 算法。
- 另外,其实还有一种折中的办法,Mark-Sweep 算法速度快,可以让虚拟机平时大多数时间都采用 Mark-Sweep 算法,暂时容忍内存碎片的存在,直到内存空间的碎片化程度已经大到影响对象分配的时候,再采用 Mark-Compact 算法收集一次,以获得规整的内存空间(基于 Mark-Sweep 算法的 CMS 收集器面临空间碎片过多时采用的就是这种处理办法)
176万+

被折叠的 条评论
为什么被折叠?



