前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么跨代引用是GC root

为什么跨代引用是GC root

作者头像
Spark学习技巧
发布2020-12-11 10:07:12
1.1K0
发布2020-12-11 10:07:12
举报
文章被收录于专栏:Spark学习技巧

转自:https://www.jianshu.com/p/671495682e46

昨日,有人在一个JVM群里问了一个问题,为什么跨代引用是gc root。这虽然是一个很简单的问题,但是其实涉及到了分代垃圾回收算法的核心理念。

gc root的基本解释

首先我们要理解一下GC root究竟是什么东西。

图:gc root

堆是被我们垃圾回收所管理的内存空间。如图,存在两种引用,一种是堆外对象对堆内对象的引用,被标注为红色;另外一种是堆内对象之间的引用,被标注为灰色。通常我们说的gc root就可以被认为是红色的那种引用,比如说栈引用堆中对象。为什么我们不认为堆内对象之间的引用是gc root呢?因为我们的对象,最终是要被外部使用的,比如说被栈引用所访问。因此,如果一大堆的堆内对象之间互相引用,但是没有任何堆外部引用,那么这部分对象实际上也是不可达的。HotSpot就是如此的,所有的堆中的对象,最终都是被栈所使用的。因而,U和V就可以看做是不可达的对象了。

分代和跨代引用

解释了gc root的基本概念后,我们要来看看分代理论了。基本上,现代垃圾回收器都是分代垃圾回收器,它建立在两个分代理论之上:

  • 弱分代假说(weak generational hypothesis):大多数对象在年轻的时候死亡;
  • 强分代假说(strong generational hypothesis):越老的对象越难死亡;

这个分代假说引申出一种垃圾回收理念:将对象依据“年龄”分配到不同的区域,每次回收只回收其中的一个区域。这也就是分代回收的基础理念。因为很显然的,如果大部分对象都是朝生夕死的,那么将它们放在一起,每次回收都能够回收到很多的空间;剩下的不容易死亡的对象,放在一起,那么可以以一种极为低的频率来回收它们。这就兼顾了垃圾回收的时间开销和内存的空间利用率。

一般的垃圾回收算法至少会划分出两个年代,年轻代和老年代。但是单纯的分代理论在垃圾回收的时候存在一个巨大的缺陷:为了找到年轻代中的存活对象,却不得不遍历整个老年代,反过来也是一样的。

图:跨代引用引起老年代的遍历

如果我们从年轻代开始遍历,那么可以断定N, S, P, Q都是存活对象。但是,V却不会被认为是存活对象,其占据的内存会被回收了。这就是一个惊天的大漏洞!因为U本身是老年代对象,而且有外部引用指向它,也就是说U是存活对象,而U指向了V,也就是说V也应该是存活对象才是!而这都是因为我们只遍历年轻代对象!

所以,为了解决这种跨代引用的问题,最笨的办法就是遍历老年代的对象,找出这些跨代引用来。这种方案存在极大的性能浪费。因为从两个分代假说里面,其实隐含了一个推论:跨代引用是极少的。也就是为了找出那么一点点跨代引用,我们却得遍历整个老年代!从上图来说,很显然的是,我们根本不必遍历R。

因此,为了避免这种遍历老年代的性能开销,通常的分代垃圾回收器会引入一种称为记忆集的技术。简单来说,记忆集就是用来记录跨代引用的表。

图:记忆集记录跨代引用

如图,在拥有记忆集的情况下,我们就可以不用遍历老年代了,这是一个巨大的性能提升!

最终解释

现在,我们设想一下,要回收年轻代,首先我们要从引用年轻代对象的外部引用开始;其次,我们要从跨代引用开始。于是我们可以很自然的得出结果:跨代引用也是gc root。

整个模型可以抽象成:

图:gc root的最终解释

附录

在引入记忆集之后,其实会有一个很有意思的问题:即老年代对象即便已经事实上不可达了,但是因为记忆集的存在,会导致从该对象出发的跨代引用依旧会被当成gc root,直至该对象被回收引起记忆集中相关条目的擦除。

图:记忆集引出的问题

如图,U已经不存在外部引用了,所以它事实上已经不可达了。但是在这个时刻,因为老年代没有发生GC,所以它依旧存活着。

  • 如果我们采用遍历老年代的方法找出跨代引用,那么我们只能找到S->P这一条。于是U和V都会被当成是不可达对象,其内存空间就可以被回收掉了。
  • 如果我们使用记忆集,那么因为U没有被GC掉,所以记忆集里面的条目U->V依旧存在,所以在年轻代回收的时候,V会被当成存活对象。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 浪尖聊大数据 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • gc root的基本解释
  • 分代和跨代引用
  • 最终解释
  • 附录
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档