Java面试知识点(五十三)垃圾回收算法
一、标记-清除算法 Mark-Sweep
这是一个非常基本的GC算法,它是现代GC算法的思想基础,分为标记和清除两个阶段:先把所有活动的对象标记出来,然后把没有被标记的对象统一清除掉。但是它有两个问题,一是效率问题,两个过程的效率都不高。二是空间问题,清除之后会产生大量不连续的内存。
二、复制算法 Copying (新生代)
复制算法是将原有的内存空间分成两块,每次只使用其中的一块。在GC时,将正在使用的内存块中的存活对象复制到未使用的那一块中,然后清除正在使用的内存块中的所有对象,并交换两块内存的角色,完成一次垃圾回收。它比标记-清除算法要高效,但不适用于存活对象较多的内存,因为复制的时候会有较多的时间消耗。它的致命缺点是会有一半的内存浪费。
2.1 HotSpot 虚拟机的改良算法
- 弱代理论 分代垃圾收集基于弱代理论。具体描述如下:
-
大多数分配了内存的对象并不会存活太长时间,在处于年轻时代就会死掉。 很少有对象会从老年代变成年轻代。
- Hotspot 虚拟机新生代内存布局及算法
-
新生代内存分配一块较大的 Eden 空间和两块较小的 Survivor 空间 每次使用 Eden 和其中一块 Survivor 空间 回收时将 Eden 和 Survivor 空间中存活的对象一次性复制到另一块 Survivor 空间上 最后清理掉 Eden 和使用过的 Survivor 空间。 Hotspot 虚拟机默认 Eden 和 Survivor 的大小比例是 8:1。 如果另一块 Survivor 空间没有足够内存来存放上一次新生代收集下来的存活对象,那么这些对象则直接通过担保机制进入老年代。
总结:年轻代分三个区。一个 Eden 区,两个 Survivor 区 (一般而言)。大部分对象在 Eden 区中生成。当 Eden 区满时,还存活的对象将被复制到 Survivor 区(两个中的一个),当这个 Survivor 区满时,此区的存活对象将被复制到另外一个 Survivor 区,当这个 Survivor 去也满了的时候,从第一个 Survivor 区复制过来的并且此时还存活的对象,将被复制 “年老区 (Tenured)”。需要注意,Survivor 的两个区是对称的,没先后关系,所以同一个区中可能同时存在从 Eden 复制过来 对象,和从前一个 Survivor 复制过来的对象,而复制到年老区的只有从第一个 Survivor 去过来的对象。而且,Survivor 区总有一个是空的。
三、标记整理算法 Mark-Compact(老年代)
标记整理算法适用于存活对象较多的场合,它的标记阶段和标记-清除算法中的一样。整理阶段是将所有存活的对象压缩到内存的一端,之后清理边界外所有的空间。它的效率也不高。
四、分代收集算法:(新生代的GC+老年代的GC)
-
少量对象存活,适合复制算法:在新生代中,每次GC时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成GC。 大量对象存活,适合用标记-清理/标记-整理:在老年代中,因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-清理”/“标记-整理”算法进行GC。
区别
(1)效率:复制算法>标记/整理算法>标记/清除算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。
(2)内存整齐度:复制算法=标记/整理算法>标记/清除算法。
(3)内存利用率:标记/整理算法=标记/清除算法>复制算法。