关于Java虚拟机垃圾收集GC的学习总结(二)

本文深入探讨了垃圾收集算法的理论与实践,包括分代收集理论、标记-清理算法、标记-复制算法和标记-整理算法。阐述了这些算法如何应对内存碎片、提高垃圾收集效率,并解释了在不同场景下选择合适算法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分代收集理论

在目前的大部分商用虚拟机中都遵循了分代收集的理论。分代收集主要基于以下两个假说:

  • 弱分代假说。绝大多数的对象的生命周期很短暂。
  • 强分代假说。经历过越多次数的垃圾收集还没被回收的对象其被回收的概率越低。

这两个假说还是很符合我的直观感受的。在编程的时候也能发现,大多数的对象用完就不会用了,而一些经常需要使用到的对象则需要它一直存在。为了提高垃圾收集的效率,于是将Java堆划分成了老年代与新生代两个区域,这样就可以针对某一个区域进行回收,而不需要访问所有的对象。很显然,新生代的回收频率比较高,但是就像前一篇中所提到的。对象之间的引用十分复杂,跨代引用是有可能出现的。为了解决这个问题可以遍历整个老年代将它们临时性的加入“GC roots”然后进行可达性分析。这与初衷不符,分代收集的目的就是为了在收集一个区域时尽量不对另一个区域采取措施,使得收集效率提高。于是有人提出了记忆集(Remember Set)的解决方案。在新生代中添加一个叫做记忆集的数据结构,它将老年代分为若干块,然后指向它们,并标记了哪些块出现了跨代引用。当对新生代进行收集时,只需要到记忆集中查看有哪些块有跨代引用并遍历那些块即可,从而避免了对整个老年代的遍历。

收集算法

之前都是收集的理论方法,只说了哪些对象需要回收、如何进行回收的大致方向,接下来说一说具体的实现方式。

标记-清理算法

顾名思义,它将所有需要被回收的对象标记起来,然后将它们回收。这个算法的效率十分不稳定,当出现大量需要被回收的对象时就需要标记大量的对象,已及对需要回收的对象进行清理。而之前的弱分代假说告诉我们,当出现了大量新对象的时候,这种情况是很容易发生的。而且光清理而不对空间进行整理的话会产生大量的内存碎片,导致大对象无法申请到空间。这在学习计算机操作系统时就已经了解过了,当时我记得解决的方案是建立一张空闲分区表,将空闲的区域链接起来,然后进行内存分配。当然,JVM并不等同于操作系统,虽然二者之间有许多联系。在JVM中内存的分配应该尽量简单,因为程序运行过程中会出现大量的内存申请,若是采取复杂的分配策略会造成很大的资源浪费。而且即使使用空闲分区表也不一定能够利用到所有的空间,当空间碎片特别多、特别小,甚至于无法再为任何对象分配连续的空间时,那么就会无限GC,系统崩溃。于是,为了解决空间碎片的问题,出现了标记-复制算法。

标记-复制算法

它将内存分为两个区域,一个区域用于实际的内存分配,一个则空闲。当发生GC后,将所有存活的对象放入空闲的内存中。然后启用这一块空闲的内存作为为对象分配空间的区域。在一开始这个方法采取的是各一半的方式。所以造成了极大的内存空间浪费,而弱分代假说告诉我们,新出现的对象能够存活下来的一般不会太多,于是出现了半区复制分代策略。它将新生代的内存采取8:2的分配方式,‘8’对应的空间称为Eden,其中的‘2’又被分成了1:1的两块空间,称为Survivor。分配空间时只使用Eden以及一块Survivor空间,另一块Survivor就用来充当之前那块空闲空间的角色。但是假说毕竟只是假说,总会有例外发生,当出现了Survivor空间无法容下所有存活对象时,就使用“逃生门”,将一部分对象直接放入老年代所在的区域。学习算法时经常碰到数组的删除与插入,对于为了保证删除后数组仍然是连续的,那么就必须把被删除元素后面的元素全部向前移动。这也可以应用到垃圾收集里来,被称为:标记-整理算法。

标记-整理算法

标记-整理算法与标记-清理算法不一样的地方在与把死亡对象删除后会做“整理”操作,也就是把还存活的对象放在一块,这样就会不会产生大量的空间碎片。这个算法看似会比标记-清理算法要好上不少,但实则不然。虽然解决了空间碎片的问题,但是移动所有的对象是需要额外的时间的,这也就意味着整个垃圾回收的时间变长了。如果移动对象与对象访问无法做到并发执行的话,那么对于对象的访问就必须等到对象移动完成后才能继续访问,这段时间里访问对象的线程将会全部暂停,从而导致高延迟。个人认为这两个方法其实可以一起使用,默认使用第一种算法,当内存里的空间碎片特别多,甚至会提前触发下一次GC时,调用一次标记-整理算法,这样既可以高效率的回收,也不必担心空间碎片过多。当然,只要存在空间碎片那么就需要使用到“空闲分区表”,这样在内存分配时还是会收到影响(写到这里,本人也不知道到底哪种方式好了,应该看场景吧,如果对延迟有较高要求的场景应该优先考虑标记-清理算法,否则应该考虑使用标记-整理算法)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值