JVM工作原理与实战(二十四):堆的垃圾回收-对象引用

简介: JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了强引用、软引用、弱引用、虚引用、终结器引用等内容。

在Java中,对象的生命周期由垃圾回收器管理。在可达性算法中,描述的对象引用通常指的是强引用,即GCRoot对象对普通对象有引用关系,只要这层关系存在,普通对象就不会被回收。但除了强引用外,Java还设计了其他几种引用方式,以应对不同的内存管理需求。

一、软引用

1.软引用的执行过程

软引用是一种相对较弱的引用关系。如果一个对象仅被软引用关联,当内存不足时,这些数据将会被虚拟机视为垃圾回收的候选对象。在JDK 1.2之后,通过SoftReference类实现了软引用。它常被用于缓存的实现。例如,当内存不足时,虚拟机首先尝试回收软引用关联的对象。如果仍不能解决内存问题,软引用中的对象将被回收。如果仍然内存不足,将抛出OutOfMemory异常。

案例:

根对象(GC Root)到目标对象(对象A)形成了引用链,对象A不可回收:

image.gif

根对象(GC Root)到目标对象(对象A)没有形成引用链,该对象被认为是不可达的,可以被安全地回收。当内存不足时,软引用中的对象(对象A)将被回收:

image.gif

软引用的执行过程如下:

  1. 将对象使用软引用包装起来,如new SoftReference<对象类型>(对象)。
  2. 当内存不足时,虚拟机尝试进行垃圾回收。
  3. 如果垃圾回收仍不能解决内存不足的问题,回收软引用中的对象。
  4. 如果依然内存不足,抛出OutOfMemory异常。

案例:

将100M的数据放入软引用中:

byte[] bytes = new byte[1024 *1024 *100];
    SoftReference<byte[]> softReference = new SoftReference<byte[]>(bytes);
image.gif

2.SoftReference队列机制

在内存不足的情况下,如果软引用所指向的对象被回收,那么SoftReference对象本身也需要被回收。为了解决这个问题,SoftReference提供了一套有效的队列机制,以确保可以准确判断哪些SoftReference对象需要被回收。这套机制使得SoftReference能够与垃圾回收器协同工作,从而优化内存管理。

SoftReference队列机制:

  • 创建与引用队列的关联:在创建SoftReference对象时,通过特定的构造器可以传入一个引用队列。这个队列用于存储SoftReference对象,以便后续的管理和回收。
  • 对象回收与队列更新:当软引用包含的对象被标记为可回收时,该软引用对象会被自动加入到指定的引用队列中。这一步骤确保了被回收对象的跟踪和管理。
  • 强引用删除:为了进一步管理内存,程序需要遍历这些引用队列,并删除SoftReference的强引用。这一操作是为了确保软引用对象不再占用额外的内存空间,从而使其可以被垃圾回收器顺利回收。

这套队列机制确保了内存管理的效率和准确性,使SoftReference能够适应不同的内存需求,有效地管理Java虚拟机的内存资源。

二、弱引用

弱引用的工作原理与软引用在很多方面是相似的,但在垃圾回收方面存在显著差异。主要区别在于,当弱引用关联的对象被垃圾回收时,不论当前系统内存空间足够与否,都会被回收。这一特性使得弱引用在处理内存管理时更为直接和高效。

在JDK 1.2版本之后,Java引入了WeakReference类来实现弱引用机制。这一设计使得弱引用主要在ThreadLocal中得到应用,为其提供了更为灵活和有效的内存管理方案。同时,弱引用对象同样可以利用引用队列进行回收。这一机制确保了垃圾回收器能够跟踪并管理弱引用对象的生命周期,从而更有效地释放内存空间。

image.gif

案例:

将100M的数据放入弱引用中:

byte[] bytes = new byte[1024 *1024 *100];
    WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes);
image.gif

三、虚引用与终结器引用

在Java的内存管理中,虚引用和终结器引用是两种较为特殊的引用类型,它们在常规开发中的使用频率相对较低。

1.虚引用

虚引用,也被称为幽灵引用或幻影引用,是一种抽象的引用关系。通过虚引用来获取一个对象是不可能的,因为虚引用仅仅提供了对对象的一个弱化形式的引用关系。其主要用途在于跟踪对象被垃圾回收的行为。当一个对象仅持有虚引用时,它就像没有任何引用一样,随时可能被垃圾回收器回收。

在Java中,PhantomReference类代表了虚引用。它允许程序监控对象何时被垃圾回收,并在回收时收到通知。这在某些场景下是有用的,例如管理外部资源或实现特定的内存管理策略。

2.终结器引用

终结器引用与对象的finalize方法相关联。当一个对象需要被回收时,终结器引用会将其关联到Finalizer类中的一个引用队列中。随后,FinalizerThread线程会从队列中取出对象并执行其finalize方法。需要注意的是,finalize方法的执行是在垃圾回收之后进行的,因此,当对象第二次被回收时,它才真正被回收。

尽管在finalize方法中可以将对象重新使用强引用关联上,但这通常是不推荐的。因为这可能导致内存泄漏或其他不可预见的问题。开发者应该谨慎处理终结器引用的使用,并确保finalize方法在执行完毕后不再保持对对象的引用。


总结

JVM是Java程序的运行环境,负责字节码解释、内存管理、安全保障、多线程支持、性能监控和跨平台运行。本文主要介绍了强引用、软引用、弱引用、虚引用、终结器引用等内容,希望对大家有所帮助。

目录
打赏
0
0
0
0
42
分享
相关文章
CMS圣经:CMS垃圾回收器的原理、调优,多标+漏标+浮动垃圾 分析与 研究
本文介绍了CMS(Concurrent Mark-Sweep)垃圾回收器的工作原理、优缺点及常见问题,并通过具体案例分析了其优化策略。重点探讨了CMS的各个阶段,包括标记、并发清理和重标记
CMS圣经:CMS垃圾回收器的原理、调优,多标+漏标+浮动垃圾 分析与 研究
JVM实战—10.MAT的使用和JVM优化总结
本文详细探讨了JVM内存管理与性能优化的关键问题。首先分析了线上大促活动引发的老年代内存泄漏及频繁FGC问题,通过MAT工具定位到本地缓存未正确处理的原因,并提出使用Ehcache等框架解决。接着讨论了百万级数据误处理导致的频繁FGC案例,深入剖析String.split()方法在特定JDK版本下的内存消耗问题,并给出多线程并发处理大数据量的优化建议。文章还总结了JVM运行原理、GC机制以及YGC和FGC的触发条件,明确了正常系统GC频率指标。最后提供了JVM性能优化的整体思路,包括新系统开发时的参数预估、压测后的调整策略以及线上系统的监控方法,同时列举了常见的FGC原因及对应解决方案。
142 79
JVM实战—10.MAT的使用和JVM优化总结
JVM实战—11.OOM的原因和模拟以及案例
本文详细探讨了Java系统中内存溢出(OutOfMemory,简称OOM)问题的成因与解决方法。首先分析了线上系统因OOM挂掉的常见场景及处理思路,接着深入讲解了JVM中可能发生OOM的三大区域:Metaspace(类信息存储区)、栈内存(线程执行方法时使用)和堆内存(对象存储区)。针对每个区域,文章通过具体代码示例模拟了内存溢出的情况,如动态生成过多类导致Metaspace溢出、无限递归调用引发栈内存溢出以及高负载下堆内存不足等问题。最后结合实际案例,如大数据处理系统因Kafka故障未正确处理数据缓存而导致OOM,以及无限循环调用或未缓存动态代理类引发的问题,给出了预防和改进措施。
142 64
JVM实战—11.OOM的原因和模拟以及案例
G1原理—5.G1垃圾回收过程之Mixed GC
本文介绍了G1的Mixed GC垃圾回收过程,包括并发标记算法详解、三色标记法如何解决错标漏标问题、SATB如何解决错标漏标问题、Mixed GC的过程、选择CollectSet的算法
G1原理—5.G1垃圾回收过程之Mixed GC
JVM实战—13.OOM的生产案例
本文详细探讨了多种线上系统中引发OOM(内存溢出)问题的原因及排查方法。内容涵盖:1)每秒仅上百请求的系统因RPC超时时间设置过长导致QPS激增而OOM;2)Jetty服务器NIO机制因堆外内存管理不当引发内存溢出;3)微服务架构下RPC调用因类定义不一致导致超大byte[]数组占用内存;4)SQL语句缺少WHERE条件查询大量数据引发OOM;5)日志分析系统因堆内存不足与递归操作耗尽内存;6)类加载器过多导致内存使用过高被OS杀死进程;7)数据同步系统频繁OOM的排查与解决;8)总结JVM参数优化、GC问题定位及OOM分析方法。
JVM实战—13.OOM的生产案例
JVM实战—9.线上FGC的几种案例
本文详细探讨了JVM性能优化中的几个关键案例与问题。首先分析了如何优化每秒十万QPS的社交APP,通过增加Survivor区大小和优化内存碎片解决频繁Full GC的问题。接着讨论了垂直电商后台系统FGC的深度优化,定制JVM参数模板以降低GC频率。还探讨了不合理设置JVM参数导致频繁FGC的情况,并提出了解决方案。此外,针对线上系统每天数十次FGC的问题,定位到大对象是主要原因,并通过调整新生代大小等参数优化。同时,分析了电商大促活动中因System.gc()调用导致系统卡死的现象,建议禁用显式GC。
JVM实战—9.线上FGC的几种案例
JVM实战—12.OOM的定位和解决
本文详细探讨了JVM内存管理中的常见问题及其解决方案,包括如何监控和报警系统的OOM异常、在内存溢出时自动Dump内存快照、解决Metaspace区域内存溢出、栈内存溢出(StackOverflowError)以及堆内存溢出(OutOfMemoryError: Java heap space)。针对每种情况,文章提供了具体的解决思路、示例代码、GC日志分析及内存快照分析方法。通过搭建系统监控体系、调整JVM参数和使用工具如MAT,可以有效定位和解决各类内存问题,优化系统性能并避免崩溃风险。
JVM实战—12.OOM的定位和解决
G1原理—3.G1是如何提升垃圾回收效率
本文深入探讨了G1垃圾回收器提升GC效率的核心机制,包括记忆集(RSet)、位图(BitMap)和卡表(CardTable)的设计与作用。记忆集通过记录跨代引用避免了不必要的老年代遍历,位图用于高效描述内存使用状态以优化标记过程,而卡表则在节约记忆集内存的同时提供更详细的引用信息。此外,文章还解析了DCQ(Dirty Card Queue)和DCQS(Dirty Card Queue Set)机制如何异步更新RSet,确保在高并发场景下的性能与准确性。这些设计共同提升了G1在标记、清理及整理内存时的效率。
G1原理—6.G1垃圾回收过程之Full GC
本文详细探讨了G1垃圾回收器对Full GC(FGC)的优化处理,涵盖FGC的前置处理、整体流程及并行化改进。重点分析了传统FGC串行化的局限性以及G1通过Region分区和RSet机制实现并行标记的优势,包括任务窃取提升效率、跨分区压缩以生成空闲Region等技术细节。此外,文章还介绍了G1的新特性——字符串去重优化,通过判断char数组一致性减少重复字符串占用内存,从而提升内存使用效率。总结部分全面回顾了G1在FGC中的各项优化措施及其带来的性能改善。
G1原理—6.G1垃圾回收过程之Full GC
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等