《深入理解 Java 虚拟机》学习笔记 Day14(垃圾收集器与内存分配:垃圾收集算法之分代收集理论)

学习内容:第3章 - 垃圾收集器与内存分配策略

垃圾收集算法

如何判断对象的消亡的角度出发,垃圾收集算法可以分为“引用计数式垃圾收集”(Reference Counting GC)和“追踪式垃圾收集”(Tracing GC)两大类,这两类也常被称为“直接垃圾收集”和“间接垃圾收集”,而因为主流的 Java 虚拟机采用的都不是引用计数法,学习中只会涉及到追踪式垃圾收集的相关概念

分代收集理论

当前的商业虚拟机的垃圾收集器,大多都遵循了“分代收集”(Generational Collection)的理论进行设计,这一理论基于两个分代假说:

  • 弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的
  • 强分代假说(Strong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以消亡

这两个分代假说奠定了多款常用垃圾收集器的设计原则:收集器应该把 Java 堆划分出不同的区域,然后将回收对象依据它的年龄(即熬过垃圾收集过程的次数)分配到不同的区域中存储。
在这之后,如果一个区域内大部分对象都是朝生夕灭的,难以熬过垃圾收集过程,把他们集中在一起,每次收集的时候就只需要关注如何保留少量存活对象而不是标记大量要被回收的对象,就可以以较低的代价回收到大量的空间;而如果剩下的都是难以消亡的对象,把他们集中放在一块,虚拟机就可以以较低的频率去回收这个区域,兼顾了垃圾收集的时间开销和内存空间的有效利用

在划分区域之后,垃圾收集器就可以每次只回收其中某一个或者某一类型的区域了,因而有了如“Minor GC”“Major GC”“Full GC”这样的回收类型划分。而针对不同区域中存储对象的存亡特征,也可以安排相匹配的垃圾收集算法,如“标记 - 复制算法”“标记 - 清除算法”“标记 - 整理算法”等。这一切都归于分代收集理论。

在现在的商用 Java 虚拟机中,设计者一般至少会把 Java 堆分为两个区域:新生代(Young Generation)和老年代(Old Generation)。在新生代中,每次垃圾收集时都会有大量对象死去,而每次回收后存活的少量对象,将会晋升到老年代中进行存放。而当前分代收集理论仍然在不断发展中,分代收集并不仅仅只是简单划分一下区域这么简单,还有一个明显的困难:对象不是孤立的,对象间会存在跨代引用

即如果当前进行一次局限于新生代区域的垃圾收集(Minor GC),但新生代中的对象完全有可能被老年代所引用,为了找出这个区域内的存活对象,就需要在固定的 GC Roots 之外再额外遍历整个老年代所有对象来确保可达性分析结果的正确性,反过来也是如此。因此,对分代收集理论补充了第三条经验法则:

跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数

其实这也是通过前两条假说可以推出来的隐含推论:存在互相引用关系的两个对象应该是倾向于同时生存或者同时消亡的,比如某个新生代对象存在跨代引用,因为老年代对象难以消亡,这个引用会使得这个新生代对象在收集时也得以存活,进而晋升到老年代中,这样跨代引用就被消除了。

因此,我们不应该为了少量的跨代引用去扫描整个老年代,也不必要浪费空间去专门记录每一个对象是否存在或者存在哪些跨代引用,只需要在新生代上建立一个全局的数据结构(被称为“记忆集”,Remembered Set)这个结构会把老年代分成若干块,标记出哪一块内存存在跨代引用。然后在发生 Minor GC 时,只有包含跨代引用的小块内存对象才会被加入到 GC Roots 进行扫描。

  • 15
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值