当前位置:  首页>> 技术小册>> 深入拆解 Java 虚拟机

第十一章 垃圾回收(上)

在Java的世界里,垃圾回收(Garbage Collection, GC)是一个至关重要的机制,它负责管理程序运行时的内存分配与回收,确保应用程序不会因为内存耗尽而崩溃。本章将深入剖析Java虚拟机(JVM)中的垃圾回收机制,首先聚焦于垃圾回收的基本概念、原理、分类以及JVM中常见的垃圾回收器(上部分),为后续深入理解垃圾回收的策略与优化打下基础。

11.1 垃圾回收的基本概念

11.1.1 内存管理与垃圾回收的必要性

Java语言的一大特点是其自动内存管理机制,即程序员无需手动释放不再使用的内存空间,这一任务由JVM的垃圾回收器自动完成。这一特性极大地简化了内存管理的复杂度,降低了内存泄漏和程序崩溃的风险。然而,自动内存管理并不意味着完全没有内存管理的问题,合理的垃圾回收策略和高效的垃圾回收器对程序性能有着重要影响。

11.1.2 垃圾的定义

在JVM中,垃圾通常指的是那些已经失去(或即将失去)任何引用关系的对象所占用的内存空间。这些对象不再被程序中的任何部分所使用,因此它们的内存可以被安全地回收,以便用于新的对象分配。

11.2 垃圾回收的基本原理

11.2.1 引用计数法

最简单直观的垃圾回收算法是引用计数法。该方法为每个对象维护一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1。任何时刻计数器为0的对象即可被认定为垃圾。然而,这种方法存在循环引用的问题,即两个对象相互引用,即使它们不再被其他任何对象引用,它们的引用计数器也不会为0,导致内存无法被回收。因此,现代JVM主要采用更为复杂的算法进行垃圾回收。

11.2.2 可达性分析算法

可达性分析算法是现代JVM中主流的垃圾回收算法。它通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,所走过的路径称为引用链(Reference Chain)。当一个对象到GC Roots没有任何引用链相连(即从GC Roots到这个对象不可达)时,则证明此对象是不可用的,即为垃圾对象。GC Roots通常包括虚拟机栈(栈帧中的局部变量表所引用的对象)、方法区中的类静态属性引用的对象、本地方法栈中JNI(即一般说的Native方法)引用的对象等。

11.3 垃圾回收的分类

根据垃圾回收发生的区域(新生代、老年代),以及回收时是否暂停用户线程的执行,垃圾回收可以分为多种类型。

11.3.1 按回收区域分类

  • 新生代回收(Minor GC/Young GC):主要回收新生代的垃圾,因为新生代中对象生命周期短,存活率低,因此新生代GC频繁但回收速度快。
  • 老年代回收(Major GC/Full GC):当老年代空间不足时,会触发老年代GC,它可能伴随新生代GC一起进行,也可能是单独进行。老年代GC的回收速度较慢,且会影响应用的性能。

11.3.2 按是否暂停用户线程分类

  • Stop-The-World(STW):在进行垃圾回收时,需要暂停用户线程的执行,直到垃圾回收完成。这是大多数传统垃圾回收器的共同特点。
  • 并发(Concurrent):垃圾回收与用户线程同时进行,减少STW的时间,提高应用性能。现代JVM中,许多垃圾回收器都支持并发回收。

11.4 JVM中的垃圾回收器(上)

JVM提供了多种垃圾回收器供用户选择或JVM自动选择,以适应不同的应用场景和性能需求。以下是一些常见的垃圾回收器(上部分):

11.4.1 Serial GC(串行垃圾回收器)

Serial GC是JVM在客户端模式下默认的垃圾回收器,它只使用一个垃圾回收线程进行垃圾回收工作,在垃圾回收时,会暂停所有的用户线程(即STW)。虽然这种回收器简单且容易实现,但由于其单线程的特性,不适合用于服务器环境。

11.4.2 Parallel GC(并行垃圾回收器)

Parallel GC是JVM在服务器模式下默认的垃圾回收器之一(另一个是CMS GC,但在后续版本中逐渐被淘汰)。与Serial GC不同,Parallel GC使用多个线程来执行垃圾回收工作,以提高垃圾回收的效率。Parallel GC支持多核CPU,并且可以通过设置JVM参数来调整垃圾回收的线程数。在垃圾回收时,同样会暂停用户线程的执行,但由于并行执行,其效率通常高于Serial GC。

11.4.3 ParNew GC

ParNew GC是Serial GC的多线程版本,除了使用多线程进行垃圾回收外,其余行为(包括GC Roots的确定、对象的可达性分析等)与Serial GC基本一致。ParNew GC主要用于与CMS GC配合使用,作为CMS GC中新生代的垃圾回收器。

11.4.4 CMS GC(Concurrent Mark Sweep,并发标记清除)

CMS GC是一种以最小停顿时间为目标的垃圾回收器,它旨在减少垃圾回收时的停顿时间,从而提高应用的响应能力。CMS GC主要工作于老年代,分为四个主要阶段:初始标记(Initial Mark)、并发标记(Concurrent Mark)、重新标记(Remark)和并发清除(Concurrent Sweep)。其中,初始标记和重新标记阶段会暂停用户线程的执行,但时间非常短;并发标记和并发清除阶段则与用户线程并发执行。然而,CMS GC存在内存碎片和浮动垃圾(Floating Garbage)等问题,且不适用于堆内存较大的情况。

11.5 总结与展望

本章详细介绍了垃圾回收的基本概念、原理、分类以及JVM中几种常见的垃圾回收器(上部分)。通过理解这些内容,读者可以对Java的垃圾回收机制有一个全面的认识。然而,垃圾回收是一个复杂且不断发展的领域,随着JVM技术的不断进步,新的垃圾回收器不断出现,如G1 GC(Garbage-First GC)、ZGC等,它们带来了更高效的垃圾回收策略和更好的性能表现。因此,在后续章节中,我们将继续探讨这些先进的垃圾回收器,以及如何在实际应用中根据具体情况选择合适的垃圾回收器,以达到最优的性能和稳定性。


该分类下的相关小册推荐: