22. 什么是垃圾回收(Garbage Collection)?JVM如何进行垃圾回收?
大约 5 分钟
垃圾回收(Garbage Collection, GC) 是Java虚拟机(JVM)自动管理内存的机制。它的主要任务是识别和回收不再被任何引用对象持有的内存,以便释放这些内存,使其能够被新的对象重新使用。这一机制帮助开发者避免手动管理内存,从而减少了内存泄漏和其他内存管理问题的风险。
一、垃圾回收的基本概念
- 堆内存管理:
- Java对象都是在堆内存(Heap Memory)中分配的。堆内存分为多个区域,通常包括新生代(Young Generation)、老年代(Old Generation),以及在较早版本中存在的永久代(PermGen)或元空间(Metaspace,JDK 8及之后的版本)。
- 可达性分析(Reachability Analysis):
- JVM使用可达性分析算法来判断对象是否存活。GC从一组称为“GC Roots”的根对象开始,通过遍历对象引用链,确定哪些对象仍然被引用。无法通过GC Roots到达的对象被视为不可达的,即不可用的对象,会被回收。
- GC Roots的例子:
- 虚拟机栈中引用的对象(如方法的局部变量)。
- 方法区中类的静态属性引用的对象。
- 方法区中常量引用的对象。
- 本地方法栈中JNI(Native方法)的引用对象。
二、JVM垃圾回收的过程
JVM的垃圾回收过程主要分为以下几个步骤和策略:
- 垃圾回收算法:
- 标记-清除算法(Mark-Sweep):
- 该算法分为“标记”和“清除”两个阶段。首先标记出所有存活的对象,随后清除未标记的对象,释放其内存。虽然简单,但清除后会产生内存碎片,影响后续的内存分配。
- 复制算法(Copying):
- 该算法将内存分为两块,每次只使用其中的一块。当这一块内存使用完时,GC将所有存活的对象复制到另一块内存,然后清空当前使用的内存。复制算法可以有效避免内存碎片问题,但需要两倍的内存空间。
- 标记-整理算法(Mark-Compact):
- 标记阶段与标记-清除算法相同,但在清除阶段,存活的对象会被移动到内存的一端,整理出连续的内存空间。这个方法解决了内存碎片问题。
- 分代收集算法(Generational Collection):
- 由于对象的生命周期有长有短,JVM将堆内存划分为新生代和老年代,并分别使用不同的垃圾回收算法。新生代使用复制算法,因为大部分对象生命周期较短;老年代使用标记-整理或标记-清除算法,因为老年代的对象存活时间较长。
- 标记-清除算法(Mark-Sweep):
- 垃圾回收器:
- Serial 收集器:
- 这是一个单线程的收集器,只适用于单CPU环境。它会暂停所有应用程序线程(“Stop-The-World”),然后进行垃圾回收,适合客户端应用程序。
- Parallel 收集器:
- Parallel收集器是一个多线程收集器,适用于多CPU环境。它通过并行处理来提高垃圾回收的吞吐量,适合服务器端应用。
- CMS 收集器(Concurrent Mark-Sweep):
- CMS收集器专注于最小化应用程序停顿时间(低延迟)。它在标记阶段采用并发方式,在应用程序运行时也进行标记和清理,减少停顿时间,适合对响应时间要求高的应用。
- G1 收集器(Garbage First):
- G1收集器是JDK 7引入的一种面向大内存、多处理器环境的收集器。它将堆划分为多个大小相等的独立区域,按照每个区域的回收收益优先回收,适合处理大堆内存下的垃圾回收需求。
- Serial 收集器:
- 垃圾回收过程中的内存区域:
- 新生代GC(Minor GC)
- 新生代GC通常会频繁发生,因为新生代中有大量短命对象。当Eden区(新生代中的一部分)满时,会触发Minor GC,将存活对象移动到Survivor区,最终晋升到老年代。
- 老年代GC(Major GC 或 Full GC)
- 当老年代的内存满时,JVM会触发Major GC(或称Full GC)。Major GC不仅会回收老年代,还可能会涉及新生代的回收。由于回收范围广,Major GC通常比Minor GC耗时更长。
- 新生代GC(Minor GC)
三、垃圾回收的触发条件
- 新生代满:当新生代的Eden区满时,会触发Minor GC,将存活对象转移到Survivor区或老年代。
- 老年代满:当老年代的内存使用接近满时,会触发Major GC或Full GC,清理老年代中的对象。
- System.gc()调用:开发者可以显式调用
System.gc()
来建议JVM进行垃圾回收,但实际执行取决于JVM的策略。 - 内存不足:当JVM内存不足以分配新对象时,可能会触发垃圾回收以释放空间,避免内存溢出(OutOfMemoryError)。
四、垃圾回收对性能的影响
- 停顿时间(Stop-the-World):在进行垃圾回收时,JVM会暂停所有应用程序线程,直到垃圾回收完成。这可能会影响应用程序的响应时间,尤其是在Full GC时。
- 吞吐量:指应用程序执行代码的时间占总时间的比率。高吞吐量意味着更少的时间花费在垃圾回收上,更多时间用于应用程序执行。
总结
垃圾回收是JVM中自动内存管理的重要机制,确保应用程序运行过程中内存的有效利用。通过不同的垃圾回收算法和垃圾回收器,JVM能够平衡应用程序性能与内存管理之间的关系,使得Java开发者可以专注于业务逻辑而不用过多关心内存管理的细节。