面试题答案
一键面试标记 - 清除算法
- 算法描述:
- 首先标记出所有需要回收的对象,一般通过从根对象(如全局变量、栈上的变量等)出发,遍历所有可到达的对象,未被遍历到的对象即为需要回收的对象。
- 标记完成后,统一回收所有被标记的对象。
- 特点:
- 优点:实现简单,不需要额外的空间记录引用计数。
- 缺点:
- 效率问题,标记和清除两个过程的效率都不高,标记阶段需要遍历所有对象,清除阶段需要遍历堆内存空间。
- 产生内存碎片,清除后会在内存中留下不连续的空闲区域,可能导致后续大对象无法分配到足够连续的内存空间。
- 适用场景:适用于对象生命周期较长、内存分配和回收频率较低的场景,例如一些服务器端应用,对内存碎片不太敏感,更注重实现的简单性。
引用计数算法
- 算法描述: 为每个对象设置一个引用计数器,每当有一个地方引用该对象时,计数器加1;当引用失效时,计数器减1。当计数器的值为0时,该对象就可以被回收。
- 特点:
- 优点:
- 回收及时,只要对象的引用计数为0,就可以立即回收,不会像标记 - 清除算法那样需要等待一个完整的回收周期。
- 实时性较好,在对象引用变化时就进行计数调整,不会出现长时间的卡顿。
- 缺点:
- 维护引用计数的开销较大,每次引用关系变化都需要更新计数器,增加了系统开销。
- 无法解决循环引用问题,若两个或多个对象相互引用,即使它们与根对象没有连接,其引用计数也不会为0,导致无法回收。
- 优点:
- 适用场景:适用于短生命周期对象较多、对实时性要求较高且不容易出现循环引用的场景,比如一些游戏开发中对短期使用的对象管理。
复制算法
- 算法描述:
- 将内存分为两块大小相等的区域,每次只使用其中一块。当这一块内存使用完后,将存活的对象复制到另一块空闲区域,然后把使用过的区域一次性清理掉。
- 特点:
- 优点:
- 简单高效,只需复制存活对象,清除操作简单,不会产生内存碎片。
- 适合回收大量短生命周期对象,因为复制操作相对标记 - 清除算法效率更高。
- 缺点:
- 内存利用率低,始终只有一半的内存可用,另一半作为备用空间。
- 复制操作对长生命周期对象开销大,每次回收都要复制存活的长生命周期对象。
- 优点:
- 适用场景:适用于新生代内存区域,新生代中对象大多生命周期短,适合使用复制算法提高回收效率。例如Java虚拟机的新生代垃圾回收就常采用类似复制算法的策略。
标记 - 整理算法
- 算法描述:
- 首先标记出所有存活的对象,与标记 - 清除算法的标记阶段类似。
- 然后将存活的对象向内存的一端移动,最后清理掉边界以外的内存空间。
- 特点:
- 优点:
- 解决了标记 - 清除算法产生内存碎片的问题,通过移动存活对象保证内存的连续性。
- 对于老年代这种对象存活率高的场景,相较于复制算法,避免了大量对象的复制操作,提高了效率。
- 缺点:
- 移动对象的操作需要调整对象的引用地址,开销较大。
- 标记和整理过程效率相对不高,标记阶段要遍历所有对象,整理阶段要移动存活对象。
- 优点:
- 适用场景:适用于老年代内存区域,老年代中对象存活率高,需要避免内存碎片,同时对效率要求不是极端苛刻,标记 - 整理算法可以较好地满足需求。