15-大厂面试题-JVM垃圾回收采用的是什么算法,有什么区别和优劣?

通过之前的学习,我们知道了JVM会通过可达性算法来筛选出哪些对象是可回收的,哪些对象是不可回收的,GCRoots对象是哪些,java的引用类型有哪些以及finlize()方法的作用。同时我们也知道了当一个对象在创建的时候是存放在堆内存中的新生代里的,那么当新生代内存满了后就会触发Minor GC;但是问题是我们如何针对新生代内存进行管理,以及如何进行回收这也是一个值得分析和探讨的问题。

这里针对新生代的垃圾回收算法,叫做复制算法

3.1复制算法

我们先来回顾下之前讲堆内存的结构分配

存储在JVM中的Java对象可以被划分为两类:

➷ 一类是生命周期较短的瞬时对象,这类对象的创建和消亡都非常迅速,生命周期短的,及时回收即可。

➷ 另外一类对象的生命周期却非常长,在某些极端的情况下还能够与JVM的生命周期保持一致。

Java堆区进一步细分的话,可以划分为年轻代(YoungGen)和老年代(oldGen),其中年轻代又可以划分为Eden空间、Survivor0空间和Survivor1空间(有时也叫做from区、to区)。

image

这里大家需要去思考,为什么JVM会分成年轻代和老年代,以及年轻代里面又为什么要再划分出三个区域,这样做的好处是什么?

我们先来分析新生代(年轻代)的复制算法以及所带来的的优劣

1969年Fenichel提出了一种称为“半区复制”(Semispace Copying) 的垃圾收集算法, 它将可用内存按容量划分为大小相等的两块, 每次只使用其中的一块。当这一块的内存用完了, 就将还存活着的对象复制到另外一块上面, 然后再把已使用过的内存空间一次清理掉。

简单点来说,就是把新生代的内存分为两块,如下图所示:

image

这时比如我们的代码如下:

<pre data-tool="mdnice编辑器" style="margin: 10px 0px; padding: 0px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">public class Test { public static void main(String[] args) { registUser(); } public static void registUser(){ User user = new User(); } } </pre>

那么对应内存中的分配就如下:

image

那么如果我们假设我们的程序不停止,依然在运行,这时不停的调用registUser()方法生产大量的User对象,对应栈帧已经退出,没有指向对应的对象,那么就会在堆内存中产生大量的垃圾对象:

image

当新生代第一块区域内容已满,装不下的时候,就会触发Minor GC回收垃圾。

这时,如果我们仅仅是采用标记算法,标记哪些对象是可回收的,哪些对象是不可回收的,然后针对可回收的内容进行回收,那么会导致一个不好的后果,就是产生大量的内存碎片。

内存碎片一般是由于空闲的连续空间比要申请的空间小,导致这些小内存块不能被利用。产生内存碎片的方法很简单,举个例:假设有一块一共有100个单位的连续空闲内存空间,范围是099。如果你从中申请一块内存,如10个单位,那么申请出来的内存块就为09区间。这时候你继续申请一块内存,比如说5个单位大,第二块得到的内存块就应该为1014区间。如果你把第一块内存块释放,然后再申请一块大于10个单位的内存块,比如说20个单位。因为刚被释放的内存块不能满足新的请求,所以只能从15开始分配出20个单位的内存块。现在整个内存空间的状态是09空闲,1014被占用,1524被占用,2599空闲。其中09就是一个内存碎片了。如果1014一直被占用,而以后申请的空间都大于10个单位,那么09就永远用不上了,造成内存浪费。如果你每次申请内存的大小,都比前一次释放的内村大小要小,那么就申请就总能成功。

image

如果内存碎片过多,就会造成大量的内存浪费,随着回收的次数越多,这样的碎片可能更多更杂乱,因此这样直接针对一块内容空间回收的做法是不可取的。

因此JVM采用了复制算法,我们图中有一块一直未使用的空间可以派上用场了。当真正发生垃圾回收的时候,JVM会将第一块空间中哪些对象是可回收的,不能回收的进行标记,然后将不可回收的对象统统复制到下面那块区域中,并且复制的时候可以紧凑的排列在一起,最大化利用内存空间:

image

那么我们可以直接一次性回收掉上面空间的所有垃圾对象,同时有新的对象产生的时候,直接放在下面这块区域进行存储即可。 那么这时上面空间就会腾出,下面空间就月会越来越多:

image

当下面区域装满的时候,同样按照刚才的逻辑复制存活对象到上面区域,一次性回收下面区域内存。两块区域内存就可以一直重复循环使用。

复制算法的缺点

那么复制算法确实可以解决内存碎片的问题,也使得我们的回收工作更加效率,不过其缺点也是显而易见的。这种复制回收算法的代价是将可用内存缩小为了原来的一半, 空间浪费未免太多了一点 。

如果我们给新生代内存分配一个G的大小,那么两块区域平均分配,各自占512MB内存,从始至终就只有一半的内存可用,这样的算法对内存的使用效率就太低了!

现在的商用Java虚拟机大多都优先采用了这种收集算法去回收新生代, IBM公司曾有一项专门研究对新生代“朝生夕灭”的特点做了更量化的诠释——新生代中的对象有98%熬不过第一轮收集。因此并不需要按照1∶ 1的比例来划分新生代的内存空间。

在1989年, Andrew Appel针对具备“朝生夕灭”特点的对象, 提出了一种更优化的半区复制分代策略, 现在称为“Appel式回收”。HotSpot虚拟机的Serial、 ParNew等新生代收集器均采用了这种策略来设计新生代的内存布局。Appel式回收的具体做法是把新生代分为一块较大的Eden空间和两块较小的Survivor空间, 每次分配内存只使用Eden和其中一块Survivor。发生垃圾搜集时, 将Eden和Survivor中仍然存活的对象一次性复制到另外一块Survivor空间上, 然后直接清理掉Eden和已用过的那块Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8∶ 1, 也即每次新生代中可用内存空间为整个新生代容量的90%(Eden的80%加上一个Survivor的10%) , 只有一个Survivor空间, 即10%的新生代是会被“浪费”的。当然, 98%的对象可被回收仅仅是“普通场景”下测得的数据, 任何人都没有办法百分百保证每次回收都只有不多于10%的对象存活, 因此Appel式回收还有一个充当罕见情况的“逃生门”的安全设计, 当Survivor空间不足以容纳一次Minor GC之后存活的对象时, 就需要依赖其他内存区域(实际上大多就是老年代) 进行分配担保(Handle Promotion) 。

image

内存的分配担保好比我们去银行借款, 如果我们信誉很好, 在98%的情况下都能按时偿还, 于是银行可能会默认我们下一次也能按时按量地偿还贷款, 只需要有一个担保人能保证如果我不能还款时, 可以从他的账户扣钱, 那银行就认为没有什么风险了。内存的分配担保也一样, 如果另外一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象, 这些对象便将通过分配担保机制直接进入老年代, 这对虚拟机来说就是安全的。

小结

本章节我们介绍了JVM垃圾回收的算法-标记复制算法,以及复制算法的缺点。下一节我们将继续介绍JVM内存的分配以及回收策略,比如:对象优先在Eden分配,大对象直接进入老年代,以及长期存活的对象将进入老年代,动态对象的年龄判断以及空间分配担保原则。

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

推荐阅读更多精彩内容