垃圾收集算法——复制算法(Copying)。

介绍了一种名为复制的垃圾收集算法,该算法通过将内存分为两个相等的部分并在每次只使用一部分的方式提高效率。此外,针对新生代的特点,详细解释了如何利用Eden和Survivor空间进行更高效的内存管理。

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

        为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,他将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半,未免太高了一点。复制算法的执行过程如下图所示。

        现在的商业虚拟机都采用这种收集算法来回收新生代,IBM公司的专门研究表明,新生代中的对象98%是“朝生夕死”的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性的复制到另外一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性的复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是每次新生代中可用内存为整个新生代容量的90%(80%+10%),只有10%的内存会被“浪费”。当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion)。

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

        这里需要说明一下,在HotSpot中的这种分代方式从最初就是这种布局,与IBM的研究并没有什么实际联系。列举IBM的研究只是为了说明这种分代布局的意义所在。

### 常见的垃圾回收算法及其工作原理 #### 1. 标记-清除(Mark-Sweep) 标记-清除算法是最早的垃圾回收算法之一。该算法分为两个阶段: - **标记阶段**:从根节点开始遍历整个对象图,标记所有可达的对象。未被标记的对象被认为是不可达的,即垃圾对象[^2]。 - **清除阶段**:扫描堆内存,释放那些未被标记的对象所占用的空间。 尽管此算法简单有效,但它存在一个问题——容易产生内存碎片,这可能导致后续的大对象分配失败[^4]。 --- #### 2. 标记-复制Copying) 标记-复制算法将堆分成两部分:From区和To区。每次仅使用其中一个区域存储活动对象,在垃圾回收时,将存活对象复制到另一个区域。 - **优点**:由于每次都清理掉一半的空间,因此不会产生内存碎片;并且复制操作通常较快[^4]。 - **缺点**:需要双倍的内存空间,造成较大的内存浪费,尤其是在存活对象比例较高的情况下表现不佳[^4]。 这种算法常用于新生代的垃圾回收,因为新生代中的大多数对象生命周期较短,死亡率高[^3]。 --- #### 3. 标记-整理(Mark-and-Compact) 为了克服标记-清除算法产生的内存碎片问题,标记-整理算法在完成标记之后,将所有的存活对象向一端移动,从而消除中间的空隙。 - **过程**:先标记所有存活对象,再将其紧凑排列在一起,最后更新指针指向新位置[^4]。 - **特点**:虽然解决了内存碎片问题,但由于涉及大量的数据搬移操作,可能会增加一定的运行开销。 --- #### 4. 分代收集理论(Generational Collection) 分代收集理论基于以下两点观察: - 大多数对象很快就会变得不可访问。 - 少数长期存活的对象倾向于持续更长时间。 基于这些特性,JVM将堆划分为不同的区域(通常是年轻代、老年代和永久代/元空间)。不同代采用不同的垃圾回收策略: - **年轻代**:频繁发生小规模的垃圾回收(Minor GC),常用 Copying 或 Mark-Sweep 算法处理。 - **老年代**:当对象经历多次 Minor GC 后仍未被回收,则进入老年代,这里发生的 Full GC 较少但耗时较长[^3]。 这种方显著提高了垃圾回收的整体效率[^2]。 --- #### 实现方式概述 各种垃圾回收器根据具体需求选择了适合自己的核心算法组合。例如: - **Serial GC 和 Parallel GC** 主要依赖于传统的 Mark-Sweep/Copying 技术来优化单线程或多线程环境下的性能[^3]。 - **CMS (Concurrent Mark Sweep)** 使用并发机制降低停顿时间,但仍可能面临内存碎片化挑战[^3]。 - **G1/GC/ZGC/Shenandoah** 结合分区技术和先进的压缩技术,进一步改善了大容量堆上的垃圾回收效果[^3]。 ```java // 示例代码展示如何设置特定的垃圾回收器 public class GCTest { public static void main(String[] args) { System.setProperty("java.vm.name", "G1"); Runtime.getRuntime().gc(); // 手动触发垃圾回收 } } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值