JVM垃圾回收二:算法实现------思维导图
程序员文章站
2022-05-21 23:29:00
...
前言
本博客为前一篇文章《JVM垃圾回收一:基本思想------思维导图》的垃圾回收算法具体设计与实现
垃圾回收算法
思维导图大纲
一. 垃圾收集算法
1. 理论(假设)基础
- 弱分代假说:绝大多数对象都是朝生夕灭的(活的很短)
- 强分代假说:熬过越多次垃圾收集过程的对象,就越难以消亡
- 跨代引用相对于同代引用来说,仅占极少数
2. 虚拟机实现
垃圾收集器应该将java堆划分出不同的区域,将对象按照其年龄分配到不同的区域来缓存"
- 新生代(Young Generation)
对朝生夕灭的对象,虚拟机将其分派在新生代区域中。垃圾回收系统只需要关注少量的存活对象,能以较低代价回收到大量的空间
- 老年代(Old Generation)
对于难以消亡的对象,虚拟机将其分派在老年代区域中。垃圾回收系统以较低的频率去回收此区域的对象,这样开销更低效果更好"
- 记忆集(Remembered Set)
- 新生代上建立的一个全局的数据结构
- 记忆集把老年代划分成若干块,标出哪一块内存存在跨代引用
- 发生Minor GC时,只有在[跨代引用关系的小块内存]里的对象才会被加到GC Roots进行扫描,缩小了回收检索的范围
3. 垃圾收集
1. 部分收集(Partial GC)
- 新生代收集(Minor GC/Young GC)
目标只是新生代的垃圾收集
- 老年代收集(Major GC/Old GC)
目标只是老年代的垃圾收集
目前只有GMS收集器会有单独收集老年代的行为
- 混合收集(Mixed GC)
目标是收集整个新生代以及部分老年代的垃圾收集
目前只有G1收集器有这样的收集策略
2. 整堆收集(Full GC)
对整个Java堆和方法区的垃圾收集
4. 垃圾收集算法
1. 标记-清除(Mark-Sweep)
- 首先标记需要回收对象;在标记完成后,统一回收掉标记的对象
- 反过来也可以,先标记不需要回收的对象;然后清除掉没有标记的对象,完成回收
- 最早也是最基础的收集算法
- 缺点
+ 执行效率不稳定:如果堆中包含大量可回收对象,则效率降低
+ 内存空间存在碎片化:碎片化越来越多可能会引起一次Full GC,花费时间长
2. 标记-复制(Mark-Copy)
- 将内存按容量分为大小相等的两块,每次只用其中一块
- 当这一块内存空间用完了,就把其中存活的对象复制到另一块
- 复制完成后,将前一块空间全部清除掉做回收
- 两块内存空间依次交替使用,来实现垃圾回收
- 缺点:可用内存只有一半,空间浪费严重 (实际上,新生代中的对象有98%熬不过第一轮收集 )
- 优化的复制-标记策略 Eden+Servivor
+ 将新生代分为一块较大的Eden空间和两块较小的Survivor空间
+ 每个具体的时间点,虚拟机只使用一块Eden和一块Survivor来储存对象
+ 垃圾回收时,将其中存活的对象复制到之前没用到的另一块Survivor中
+ Hotspot虚拟机的Serial、ParNew等新生代收集器都采用此策略
+ 老年代因为存活率高,会有大量存活对象,不适合用复制算法
3. 标记-整理(Mark-Compact)
标记整理算法与标记复制很像,不同点在于:不复制,是整理
- 让所有的对象都向内存空间一端移动,然后直接清理掉边界以外的内存
- 存活对象过多的话,""移动""对象负重较大,此时必须全程暂停用户应用程序,会影响效果和体验
- 不整理(移动)又会出现标记-清除的碎片化
+ 妥协的优化方案
- 让虚拟机平时多数时间采用标记-清除算法,暂时容忍碎片化存在
- 当碎片化多到影响对象内存分配是,再采用标记-整理算法收集一次
- 基于标记-清除算法的CMS收集器在碎片过多时,会采用此方法"
+ 此算法多用在老年代
下一篇: A*算法简介