JVM工作原理与实战(二十三):堆的垃圾回收-引用计数法和可达性分析法

简介: JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了判断堆上的对象是否可以回收的方法(引用计数法、可达性分析法)、查看垃圾回收日志等内容。

一、判断堆上的对象是否可以回收

在垃圾回收过程中,首要任务是判断哪些对象可以安全地回收。常见的判断方法主要有两种:引用计数法可达性分析法

1.引用计数法

引用计数法是一种直观且简单的垃圾回收策略。每个对象都持有一个引用计数器,当一个对象被引用时,其计数器加1;当引用被解除时,计数器减1。当计数器归0时,对象即被认为是可以回收的。

image.gif

引用计数法的优点在于其实现简单,对于某些特定场景(如C++中的智能指针)非常适用。然而,它也存在一些明显的缺点:

  • 每次引用或取消引用都需要更新计数器,这可能对系统性能产生影响。尤其是在对象引用频繁增减的情况下,这可能导致大量的更新操作,从而影响程序的运行效率。
  • 引用计数法无法处理循环引用的情况。例如,当对象A引用对象B,同时对象B也引用对象A时,即使这两个对象之间没有其他外部引用,它们的引用计数也不会归0,从而导致无法正常回收,造成内存泄漏。

2.可达性分析算法

相比之下,可达性分析算法更为复杂,但它能够解决循环引用问题。在可达性分析中,所有对象被分为两类:垃圾回收的根对象(GC Root)和普通对象。这些根对象通常是程序中可以直接访问的对象。算法通过追踪从根对象到目标对象的引用链,来判断一个对象是否可达。如果一个对象从任何根对象都无法达到,那么这个对象就被认为是不可达的,可以被安全地回收。

案例:

在图中,A对象引用了B对象,B对象又引用了C和D对象,从而形成了一个引用链。可达性分析算法的核心思想在于,如果一个对象无法从垃圾回收的根对象(GC Root)可达,那么这个对象就可以被安全地回收。反之,如果一个对象可以从某个GC Root对象可达,那么这个对象就被认为是活动的,不可被回收。

image.gif

在Java中,就采用了可达性分析算法来判定对象是否可以回收。所有的根对象都存在于线程的栈中或者其他一些固定区域(例如JDK中的强引用、软引用、弱引用、虚引用)。如果一个对象被根对象直接或间接引用,那么这个对象就被认为是活动的、不可被回收的;反之,如果一个对象没有任何根对象引用它,那么这个对象就可以被垃圾回收。

可达性分析算法的主要优点是它可以处理复杂的引用关系和避免循环引用的问题。然而,它也有一些缺点:

  • 可达性分析算法需要追踪和记录所有的引用关系,这可能会增加内存和CPU的使用。
  • 如果一个程序在运行过程中改变了引用关系(例如在Java中的null指针异常),这可能会影响到垃圾回收的结果。
  • 对于一些动态生成的对象或者短生命周期的对象,可达性分析可能无法有效地判定其是否可以回收。

GC Root对象:

在垃圾回收过程中,GC Root对象是指垃圾回收的起始点。这些对象是可达的,并且通过引用关系可以访问到堆上的其他对象。常见的GC Root对象包括:

  • 线程Thread对象:每个线程在Java虚拟机中都有一个对应的Thread对象,这些对象引用线程栈帧中的方法参数、局部变量等,为垃圾回收提供了可达性路径。
  • 系统类加载器加载的java.lang.Class对象:系统类加载器加载的java.lang.Class对象,这些对象引用类中的静态变量。
  • 监视器对象:当一个线程执行同步代码块或同步方法时,会创建一个监视器对象来保存同步锁的信息。
  • 本地方法调用时使用的全局对象:在使用本地方法(native method)时,Java虚拟机可能会创建一些全局对象。

二、查看垃圾回收日志

要获取垃圾回收的详细信息,可以使用-verbose:gc参数。该参数提供了关于垃圾回收操作的详细日志输出。

-verbose:gc

image.gif

通过使用此参数,可以获取有关垃圾回收的详细信息,包括每次垃圾回收的类型、回收前和回收后的内存使用情况等,这些信息对于分析和优化垃圾回收性能非常有用。

image.gif


总结

JVM是Java程序的运行环境,负责字节码解释、内存管理、安全保障、多线程支持、性能监控和跨平台运行。本文主要介绍了判断堆上的对象是否可以回收的方法(引用计数法、可达性分析法)、查看垃圾回收日志等内容,希望对大家有所帮助。

相关文章
|
3月前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
88 0
|
3月前
|
算法 网络协议 Java
【JVM】——GC垃圾回收机制(图解通俗易懂)
GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
|
3月前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
2月前
|
存储 设计模式 监控
快速定位并优化CPU 与 JVM 内存性能瓶颈
本文介绍了 Java 应用常见的 CPU & JVM 内存热点原因及优化思路。
622 166
|
4月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
739 1
|
5天前
|
存储 设计模式 监控
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
如何快速定位并优化CPU 与 JVM 内存性能瓶颈?
|
5月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
58 4
|
16天前
|
存储 算法 Java
JVM: 内存、类与垃圾
分代收集算法将内存分为新生代和老年代,分别使用不同的垃圾回收算法。新生代对象使用复制算法,老年代对象使用标记-清除或标记-整理算法。
19 3
|
3月前
|
存储 Java 程序员
【JVM】——JVM运行机制、类加载机制、内存划分
JVM运行机制,堆栈,程序计数器,元数据区,JVM加载机制,双亲委派模型
|
3月前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。