Carson带你学JVM:这是一份全面 & 详细的垃圾收集算法(GC)讲解攻略

前言

  • 不同的内存区域采用不同的垃圾收集算法
  • 而不同垃圾收集算法决定了垃圾收集的效率 & 效果
  • 本文将全面讲解垃圾收集算法,包括标记-清除、复制、标记-整理等,希望你们会喜欢

Carson带你学JVM系列文章,具体如下:
Carson带你学JVM:这是一份全面 & 详细的JVM学习指南
Carson带你学JVM:图文解析Java虚拟机内存结构
Carson带你学JVM:Java对象的创建、内存布局 & 访问定位全过程解析
Carson带你学JVM:Java对象如何判断存活原则-引用计数法 & 引用链法
Carson带你学JVM:这是一份全面 & 详细的垃圾收集算法(GC)讲解攻略
Carson带你学JVM:常见的垃圾收集器学习指南
Carson带你学JVM:类加载的全过程解析
Carson带你学JVM:你真的了解类加载器吗?(含双亲委派模型)
Carson带你学JVM:方法分派模型-静态分派、动态分派


目录

示意图

1. 垃圾收集算法 类型

  • 垃圾收集算法 类型 分为4类,如下图:
垃圾收集算法类型
  • 下面我将对每个进行详细讲解。

2. 标记-清除 算法

这是 垃圾收集算法中 最最基础的算法。

2.1 算法思想

算法分为两个阶段:

  1. 标记阶段:标记出所有需要回收的对象;
  2. 清除阶段:统一清除(回收)所有被标记的对象。

下面主要讲解标记阶段。标记阶段主要分为:(先进行可达性分析)

  1. 第一次标记 & 筛选
  2. 第二次标记 & 筛选

a. 可达性分析

阅读前请看文章

b. 第一次标记 & 筛选

i. 方式描述

对象 在 可达性分析中 被判断为不可达后,会被第一次标记 & 筛选

a. 不筛选 = 继续留在 ”即将回收“的集合里,准备被回收
b. 筛选 = 从 ”即将回收“的集合取出

ii. 筛选的标准

该对象是否有必要执行 finalize()方法

  1. 若有必要执行(人为设置),则筛选出来,进入下一阶段:第二次标记 & 筛选;
  2. 若没必要执行,判断该对象死亡,不筛选 并等待回收

当对象无 finalize()方法 或 finalize()已被虚拟机调用过,则视为“没必要执行”


c. 第二次标记 & 筛选

当对象经过了第一次的标记 & 筛选,会被进行第二次标记,并被进行 筛选

i. 方式描述

该对象会被放到一个 F-Queue 队列中,并由 虚拟机自动建立、优先级低的Finalizer 线程去执行 队列中该对象的finalize()

  1. finalize()只会被执行一次
  2. 但并不承诺等待finalize()运行结束。这是为了防止 finalize()执行缓慢 / 停止 使得 F-Queue队列其他对象永久等待。

ii. 判断标准

在执行finalize()过程中,若对象依然没与引用链上的GC Roots 直接关联 或 间接关联(即关联上与GC Roots 关联的对象),那么该对象将被判断死亡,不筛选(留在”即将回收“集合里) 并 等待回收


总结

总结图

2.2 优点

算法简单、实现简单

2.3 缺点

  • 效率问题:即 标记和清除 两个过程效率不高
  • 空间问题:标记 - 清除后,会产生大量不连续的内存碎片。
示意图

这导致 以后程序 需要分配较大空间对象时 无法找到足够大的连续内存 而被迫 触发另外一次垃圾收集行为,这导致非常浪费资源。

下面继续介绍的算法就是为了解决上述两个问题的。

2.4 应用场景

对象存活率较低 & 垃圾回收行为频率低 的场景

如老年代区域,因为老年代区域回收频次少、回收数量少,所以对于效率问题 & 空间问题不会很明显。


3. 复制算法

该算法的出现是为了解决 标记-清除算法中 效率 & 空间问题的。

3.1 算法思想

  • 将内存分为大小相等的两块,每次使用其中一块;
  • 当 使用的这块内存 用完,就将 这块内存上还存活的对象 复制到另一块还没试用过的内存上
  • 最终将使用的那块内存一次清理掉。

示意图如下:

示意图

3.2 优点

  1. 解决了标记-清除算法中 清除效率低的问题

每次仅回收内存的一半区域

  1. 解决了标记-清除算法中 空间产生不连续内存碎片的问题

将已使用内存上的存活对象 移动到栈顶的指针,按顺序分配内存即可。

3.3 缺点

  1. 每次使用的内存缩小为原来的一半。
  2. 当对象存活率较高的情况下需要做很多复制操作,即效率会变低

3.4 应用场景

对象存活率较低 & 需要频繁进行垃圾回收 的区域

如新生代区域

3.5 特别注意

a. 背景
新生代区域在进行垃圾回收时,98%对象都必须得回收

b. 问题
复制算法中 每次使用的内存缩小为原来的一半 利用率低 & 代价太高

c. 解决方案

  • 不 按 1:1的比例 划分内存,而是 按8:1:1比例 将内存划分为一块较大的 Eden 和两块较小的 Survivor 区域(From SurvivorTo Survivor
示意图
  • 每次使用EdenFrom Survivor区域;
  • 用完后就 将上述两块区域存活的对象 复制到To Survivor区域上
  • 最终一次清理掉EdenFrom Survivor区域

使用逻辑 同 改进前


很多同学会问,假如 EdenFrom Survivor区域上存活对象所需内存大小 > To Survivor区域怎么办?

解决方案:依赖老年代内存区域 做 内存分配担保。

To Survivor区域 存不下来的对象 会通过 内存分配担保机制 暂时保存在老年代


4. 标记 - 整理 算法

此算法类似于第一种标记 - 清除 算法,只是在中间加多了一步:整理内存。

4.1 算法思路

算法分为三个阶段:

  1. 标记阶段:标记出所有需要回收的对象;
  2. 整理阶段:让所有存活的对象都向一端移动
  3. 清除阶段:统一清除(回收)端以外的对象。

示意图如下:

示意图

4.2 优点

  • 解决了标记-清除算法中 清除效率低的问题:一次清楚端外区域
  • 解决了标记-清除算法中 空间产生不连续内存碎片的问题:将已使用内存上的存活对象 移动到栈顶的指针,按顺序分配内存即可。

4.3 应用场景

对象存活率较低 & 垃圾回收行为频率低 的场景

如老年代区域,因为老年代区域回收频次少、回收数量少,所以对于效率问题 & 空间问题不会很明显。


5. 分代收集算法

主流的虚拟机基本都采用该算法,下面会着重讲解。

5.1 算法思路

  • 根据 对象存活周期的不同Java堆内存 分为:新生代 & 老年代 。分配比例如下:
示意图
  • 根据 两块区域特点 选择 对应的垃圾收集算法(即上面介绍的算法),具体细节请看下图
示意图

5.2 具体存储过程

  1. 新建的对象 一般会被优先分配到新生代的Eden区、From Survivor
  • 大对象(如很长的字符串以及数组)会直接分配到老年代,这是为了避免在 Eden 区 和 Survivor区之间发生大量的内存复制(因为新生代会采用复制算法进行垃圾收集)
  1. 这些对象经过第一次 Minor GC后,若仍然存活,将会被移到To Survivor

一次清理掉EdenFrom Survivor区域

  1. To Survivor 区每经过一轮 Minor GC ,该对象的年龄就+1
  2. 当对象年龄达到一定时(阈值默认=15),就会被移动到老年代。
  • 即新生代的对象在存活一定时间后,会被移动存储到老年代区域。
  • 还有一种 新生代对象被移懂到老年代区域 的情况是:动态对象年龄判定。即如果在Survivor区中 所有相同年龄对象的大小总和 大于
    Survivor区内存大小一半时,所有大于或等于该年龄的对象都会直接进入老年代。

特别注意

From SurvivorTo Survivor之间会经常互换角色。

每次发生GC时,把Eden区和 From Survivor区中 存活且没超过年龄阈值的对象 复制到To Survivor区中(此时To Survivor变成了From Survivor),然后From Survivor清空(此时From Survivor变成了To Survivor

5.2 优点

效率高、空间利用率高

根据不同区域特点 选择 不同的垃圾收集算法

5.3 应用场景

现在主流的虚拟机基本都采用 分代收集算法 ,即根据不同区域特点选择不同垃圾收集算法。

  1. 新生代 区域:采用 复制算法
  2. 老年代 区域:采用 标记-清除 算法、标记 - 整理 算法

6. 总结

用一张图总结上述4个垃圾收集算法

总结

接下来我会对Java虚拟机(JVM)进行详细的分析,欢迎关注Carson_Ho的简书,不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度


请点赞!因为你的鼓励是我写作的最大动力!

Carson带你学JVM系列文章,具体如下:
Carson带你学JVM:这是一份全面 & 详细的JVM学习指南
Carson带你学JVM:图文解析Java虚拟机内存结构
Carson带你学JVM:Java对象的创建、内存布局 & 访问定位全过程解析
Carson带你学JVM:Java对象如何判断存活原则-引用计数法 & 引用链法
Carson带你学JVM:这是一份全面 & 详细的垃圾收集算法(GC)讲解攻略
Carson带你学JVM:常见的垃圾收集器学习指南
Carson带你学JVM:类加载的全过程解析
Carson带你学JVM:你真的了解类加载器吗?(含双亲委派模型)
Carson带你学JVM:方法分派模型-静态分派、动态分派

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • 1、自己的工作能力得到提高,组织能力管理能力协调能力,不再内敛,勇敢表达自己的想法。 2、不管通过什么方式,剔除五...
    二姑娘呦阅读 152评论 0 0
  • 我为什么选择做安然? 我一定要过更好的生活,一定要豪车,一定不允许前女友的悲剧再次发生(因为自己没有钱)。 我一定...
    黎帅阅读 135评论 0 0
  • 尊敬的客户们: 你们好,我公司将于9月24日中秋佳节,放假一天,于9月25日正式上班,在放假期间如有不便之...
    臧冰阅读 580评论 0 0
  • codezwc阅读 323评论 0 0