Java中的垃圾回收机制,你知道几个?

开发 前端
Java 的垃圾回收机制是一个复杂而高效的内存管理系统,通过不同的算法和策略,可以最大限度地提高内存利用率,降低内存管理的复杂性。

Java 的垃圾回收机制,包括每种机制的详细原理、实现细节、适用场景、调优策略以及相关的 JVM 参数。

1. 标记-清除(Mark-and-Sweep)

工作原理

  • 标记阶段

从根对象开始,递归遍历所有可达的对象(包括静态变量、栈帧中的对象、JNI 引用等),并将这些对象标记为“存活”。

使用数据结构(如布尔数组或位图)来跟踪对象的标记状态。

  • 清除阶段
  • 遍历堆内存中的对象,回收未被标记的对象。
  • 直接将未标记对象的内存空间归还给堆。

实现细节

  • 数据结构:使用位图来表示对象的存活状态,以减少空间开销。
  • 内存分配:标记-清除算法通常不需要复杂的内存分配策略,但可能会引入内存碎片。

优缺点

  • 优点

实现简单,能处理复杂的对象图。

可以回收大对象,不会产生额外的开销。

  • 缺点
  • 清除阶段导致内存碎片,可能造成内存使用效率降低。
  • 标记和清除阶段可能导致长时间的停顿,影响应用性能。

适用场景

  • 适用于小型应用或特定场景下的对象回收,但通常不适合大规模应用。

2. 复制(Copying)

工作原理

  • 内存分配

将堆分为两个区域:活跃区域和空闲区域。

当活跃区域满时,将存活对象复制到空闲区域,并清空活跃区域。

实现细节

  • 内存布局:使用两个相同大小的内存区域,使用指针指向当前的活跃区域。
  • 对象移动:通过指针记录存活对象的位置,避免重复复制。

优缺点

  • 优点

避免了内存碎片,存活对象是连续的。

复制过程相对快速,适合频繁的对象创建和销毁场景。

  • 缺点
  • 需要额外的内存,实际使用两倍的内存。
  • 长生命周期的对象会频繁复制,造成性能损失。

适用场景

  • 适合短生命周期对象的场景,如游戏开发或快速创建对象的应用。

3. 标记-整理(Mark-and-Compact)

工作原理

  • 标记阶段:与标记-清除相同,遍历对象图并标记存活对象。
  • 整理阶段:移动存活对象到内存的一个端,清除未标记的对象,并更新指向这些对象的引用。

实现细节

  • 移动对象:使用指针数组来跟踪存活对象的位置,以更新引用。
  • 内存重分配:在整理阶段,不仅清除未标记对象,还通过移动存活对象来压缩内存。

优缺点

  • 优点

消除了内存碎片,优化内存使用效率。

组织良好的内存布局,提高访问速度。

  • 缺点
  • 移动对象带来额外的开销,特别是大量对象时。
  • 更新引用可能影响性能。

适用场景

  • 适合内存使用效率要求高的应用,如大规模服务器应用。

4. 分代收集(Generational Collection)

概念

  • 年轻代(Young Generation)

包含新创建的对象,分为 Eden 区和两个 Survivor 区。

由于大多数对象的生命周期短,因此在这里进行频繁的垃圾回收(Minor GC)。

  • 老年代(Old Generation)
  • 存活时间较长的对象。
  • 只有在年轻代的垃圾回收无法回收更多空间时,才会进行老年代的垃圾回收(Major GC)。

实现细节

  • Eden 区:存放新创建的对象,使用复制算法。
  • Survivor 区:存放存活下来的对象,进行多次的复制和晋升。

优缺点

  • 优点

高效利用内存,通过分代机制提高垃圾回收的频率和效率。

大多数对象在年轻代中会很快被回收,降低了老年代的回收频率。

  • 缺点
  • 对于老年代的回收可能导致长时间的停顿。
  • 对于长生命周期的对象,分代的划分需要合理设计。

适用场景

  • 适用于大多数 Java 应用,特别是大型服务器应用。

5. 垃圾回收器

1. Serial GC

  • 特点

仅使用一个线程进行标记、清除和整理。

  • 实现细节
  • 适合小堆内存和单核处理器。

2. Parallel GC

  • 特点

多线程的实现,利用多个 CPU 核心。

  • 实现细节
  • 可以调节线程数以提高吞吐量,通常用于大堆内存。

3. Concurrent Mark-Sweep (CMS) GC

  • 特点

并发标记和清除,降低停顿时间。

  • 实现细节
  • 使用多线程进行标记阶段,清除阶段也可以并发执行。

4. G1 GC

  • 特点

将堆分为多个区域,按需回收。

  • 实现细节
  • 可以预测停顿时间,适用于大内存和低延迟的应用。

5. ZGC

  • 特点

低延迟回收,支持大堆内存。

  • 实现细节
  • 使用并行和并发技术,实现几乎不停止应用。

6. Shenandoah GC

  • 特点
  • 高效低延迟,支持较大的堆。
  • 实现细节
  • 在回收阶段,避免全停顿,通过并行和分区回收对象。

调优垃圾回收器

1. JVM 参数

  • 选择垃圾回收器

使用 -XX:+UseG1GC,-XX:+UseParallelGC 等来指定垃圾回收器。

  • 设置堆内存大小
  • 使用 -Xms 和 -Xmx 来设置初始和最大堆内存大小。

调节年轻代和老年代的比例


  • 使用 -XX:NewRatio 来设置年轻代与老年代的比例。

调节线程数量


  • 使用 -XX:ParallelGCThreads 来设置并行回收的线程数量。

监控和分析工具


  • 使用 JVisualVM、Java Mission Control、JConsole 等工具来监控内存使用和垃圾回收的性能。

总结

Java 的垃圾回收机制是一个复杂而高效的内存管理系统,通过不同的算法和策略,可以最大限度地提高内存利用率,降低内存管理的复杂性。理解和优化垃圾回收器是提升 Java 应用性能的关键之一。在不同的应用场景下,选择合适的垃圾回收机制和调优策略,可以显著改善应用的响应时间和资源使用效率。

责任编辑:武晓燕 来源: 海燕技术栈
相关推荐

2017-06-12 17:38:32

Python垃圾回收引用

2009-06-23 14:15:00

Java垃圾回收

2011-07-04 16:48:56

JAVA垃圾回收机制GC

2011-06-28 12:39:34

Java垃圾回收

2015-06-04 09:38:39

Java垃圾回收机

2010-10-13 10:24:38

垃圾回收机制JVMJava

2017-08-17 15:40:08

大数据Python垃圾回收机制

2010-09-25 15:33:19

JVM垃圾回收

2017-03-03 09:26:48

PHP垃圾回收机制

2021-11-05 15:23:20

JVM回收算法

2023-03-26 22:48:46

Python引用计数内存

2011-06-28 10:19:40

C#开发

2010-09-26 14:08:41

Java垃圾回收

2021-05-27 21:47:12

Python垃圾回收

2010-09-25 15:26:12

JVM垃圾回收

2010-09-16 15:10:24

JVM垃圾回收机制

2021-12-07 08:01:33

Javascript 垃圾回收机制前端

2016-08-11 15:02:54

Java垃圾回收机制内存

2016-08-11 14:26:29

Java垃圾回收机制内存分配

2017-10-12 12:41:11

PHP圾回收机制变量容器
点赞
收藏

51CTO技术栈公众号