JVM的垃圾收集技术简介

内存动态分配和垃圾收集这些自动化技术使得Java语言比C++语言更加简单易用,经过几十年的发展,这些技术也日趋成熟。虽然这些技术处于底层且较为成熟,但我们仍有必要学习并掌握它,因为当GC成为系统高并发的瓶颈时,我们就需要进行GC调优。本文不涉及GC调优的相关内容,仅仅是作为当前Java虚拟机GC技术的一个简单入门介绍。

总的来说,垃圾收集技术紧紧围绕两个核心:

  • 哪些对象需要回收?(如何判断对象是否存活)
  • 如何回收?(常见的垃圾回收算法简介)

下面我们针对这两个核心对GC进行简单介绍,并讲解一下当下常用的垃圾收集器的基本过程。

如何判断对象是否存活

判断对象是否存活的常用算法有引用计数法可达性分析法,Java虚拟机一般使用可达性分析法。

引用计数法的思想十分简单,它使用一个变量来记录对象被引用的次数,当变量值为0时则该对象可被回收。但引用计数法无法解决循环引用的问题,例如A引用B,B引用A,但没有其它对象引用A和B,理论上讲此时A和B都已经是不可能再被访问到应当被回收,但实际上A和B的引用计数都为1,引用计数算法也就无法回收它们。

可达性分析算法的基本思想是从一些称为“GC Roots”的对象出发,根据引用关系向下搜索,可以被访问到的对象是存活的,不能被访问到的对象则是可被回收的。例如,下图中的Object 5,6,7就是应当被回收的对象。JVM中可以作为GC Roots的对象包括类中静态属性引用的对象等。

常见的垃圾回收算法简介

分代假说

当下的垃圾回收器大多基于“分代假说”设计,分代假说是对程序运行情况的两条经验总结:

  • 绝大多数对象都是朝生夕死的
  • 熬过垃圾收集次数越多的对象越难以消亡

根据分代假说,大多数垃圾收集器的设计原则为:将对象根据其年龄(熬过垃圾收集的次数)存放在不同的内存区域,并针对该内存区域中对象的存亡特征执行相应的垃圾回收策略。如果一个区域内的对象大多数都是朝生夕死的,那么垃圾回收时就可以只关注少部分存活对象即可,从而用较低代价回收到大量空间;如果一个区域内的对象大多数是难以消亡的,那么虚拟机就可以减少对该区域的垃圾回收频率,从而兼顾了垃圾回收的时间开销的回收效率。当下虚拟机的具体实现中多把内存区域分为新生代和老年代,并相应的设计了标记-清除算法、标记-复制算法和标记-整理算法。

标记-清除算法

标记-清除算法的基本思想为:首先使用可达性分析法标记出所有需要被回收的对象,标记完成后统一回收被标记的对象。该算法缺点有二:第一,当需要被回收的对象较多时,其效率较低;第二,会造成内存碎片化问题。算法示意图如下:

标记-复制算法

标记-清除算法的基本思想为:将内存区域一分为二,每次只使用其中之一,垃圾回收时将这一块内存上的存活对象复制到另一块未使用的内存区域中去,然后将这一块内存一次性整体回收。这种算法解决了标记-清除算法存在内存碎片的问题,但缺陷是存在空间浪费。算法示意图如下:

标记-整理算法

标记-整理算法的基本思想为:将所有存活对象向内存空间的一端移动,然后直接清理掉边界以外的内存。这种算法解决了空间浪费的问题。算法示意图如下:

三种算法总结

新生代中存活对象较少,需要被回收的对象较多;老年代中存活对象较多,需要被回收的对象较少。三种算法的适应场景如下:

  • 标记-清除算法:该算法标记完成后统一回收被标记的对象,所以在被回收对象较少存活对象较多的老年代中效率更高
  • 标记-复制算法:该算法将存活对象复制到保留内存中去,所以在存活对象较少被回收对象较多的新生代中效率更高
  • 标记-整理算法:该算法将存活对象向一边靠拢,效率比标记-复制算法低,一般用在老年代中

标记-复制算法的具体实现并不会简单粗暴的按照1:1的比例来划分新生代的内存空间,有研究表明98%的新生代对象都熬不过第一轮垃圾收集,因此可以采用一种Apple式回收的策略:将新生代划分为一块Eden区和两块Survivor区,Eden:Survivor = 8:1,每次使用Eden区和一块Survivor区,回收时将其存活对象复制到另一块Survivor中,所以只有10%的新生代空间是被浪费的。

标记-清除算法和标记-整理算法都用于老年代的回收,两种算法的根本区别是是否需要移动存活对象。移动存活对象,内存回收时更加复杂,而且移动过程需要STW(Stop The World, 即暂停用户线程,因为移动对象会改变内存地址,需要更新相关对象的引用);而不移动,内存分配时更加复杂,还产生空间碎片。因此,从垃圾收集的停顿时间来看,不移动对象停顿时间会更短,甚至可以不需要停顿,但是从整个程序的吞吐量来看,移动对象会更划算。

CMS的垃圾收集过程

CMS(Concurrent Mark Sweep)收集器专注于负责老年代的垃圾收集,以获取最短回收停顿时间为目标,所以基于标记-清除算法实现。整个过程分为四步:

  • 初始标记:需要STW,仅标记和GC Roots直接关联的对象,速度快
  • 并发标记:不需要STW,从GC Roots直接关联的对象出发并发标记,和用户线程并发运行
  • 重新标记:需要STW,修正并发标记过程中因用户线程并发运行导致的变动(主要是垃圾变为非垃圾的修正)
  • 并发清除:不需要STW,清理掉死亡对象,因为使用标记-清除算法不需移动对象,所以可以和用户线程并发运行

CMS运行示意图如下:

CMS的缺点有三:

  • 吞吐量低,并发过程占用CPU
  • 无法处理并发过程中新产生的浮动垃圾
  • 标记-清除算法导致的内存碎片化问题

G1的垃圾收集过程

G1(Garbage First)收集器是全功能的垃圾收集器,从JDK 9开始称为服务端模式下的默认收集器。G1不再单单针对新生代或者老年代,而是面向整个堆:G1将堆划分为多个大小相等的独立区域,每个区域都可以根据需要扮演Eden、Survivor或者老年代,优先针对垃圾最多回收价值最大的区域进行回收。G1的设计目标是在延迟可控的情况下尽可能追求高的吞吐量。

参考文献

【1】《深入理解Java虚拟机(第3版)》周志明著,机械工业出版社。


每日学习笔记,写于2020-04-17 星期五

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