【JVM】Java中有哪些垃圾回收算法?
最近在学习JVM相关内容,想分享一下Java中垃圾回收算法,也是JVM重要的一part,如果对你有帮助,欢迎点赞、收藏、评论!
常见的垃圾回收算法有以下三种:
标记-清除算法、标记-整理算法、复制算法。
每种算法有不同的适用场景与存在的问题,下面细聊。
1.标记-清除算法(Mark-Sweep):
- 流程: 先遍历堆中的对象,标记出存活的对象,然后原地把其他的垃圾对象(未标记的)清除。
- 优点: 比较简单,可以处理堆中的所有对象。
- 缺点: 标记和清除过程会出现碎片,影响后续内存分配。
2.标记-整理算法(Mark-Compact):
- 流程: 遍历堆中的对象,标记出存活对象,先把这些存活对象先整理到一侧,然后把(未标记的)垃圾对象清除。与标记-清除算法的区别是:先整理,再清除。
- 优点: 避免了内存碎片。
- 缺点: 由于要移动对象,有额外的开销。
3.复制算法:
通过复制存活对象来清除垃圾对象。
三步走: 分块、复制、交换。
步骤1.内存分块
将堆内存划分为大小相等的两块区域(通常称为 “From 空间” 和 “To 空间”),同一时间只使用其中一块(From 空间),另一块(To 空间)保持空闲。
步骤2.标记与复制
当 From 空间快满时,触发垃圾回收:
**标记:**遍历 From 空间,识别所有存活对象(被根对象直接或间接引用的对象)。
复制:将所有存活对象按顺序复制到 To 空间(紧凑排列,无碎片)。
**清除:**复制完成后,From 空间中剩余的对象都是垃圾,直接清空整个 From 空间。
步骤3.空间交换
回收结束后,From 空间和 To 空间的角色互换:原来的 To 空间变为新的 From 空间(供程序分配内存),原来的 From 空间变为新的 To 空间(空闲)。
以上步骤完成后,TO区总是空闲的,FROM区提供可分配的内存空间。
优点:
1.无内存碎片:存活对象被连续复制到TO空间,内存布局紧凑。
2.回收高效:无需标记垃圾(只需标记存活对象),也无需逐个清除垃圾,直接清空整个 From 空间即可,回收过程简单快速。
3.适合新生代:年轻代对象 “朝生夕死”(存活时间短,存活对象少),复制时只需复制少量对象,成本低。
缺点:
1.内存利用率低:因为TO空间处于空闲状态,所以实际空间利用率只有50%。
2.不适合存活对象多的场景:比如老年代,复制需要大量时间,性能较低。
3.对象引用需要更新:复制对象后,原对象的引用地址会发生变化,需要遍历并更新所有引用该对象的指针,增加额外开销。