AI大模型教程
一起来学习

JVM学习日记(八)Day8

在讲本篇之前回顾一下之前的知识,请问什么是并行、并发、串行?主包之前是有讲过的就是在JVM学习日记(二)Day2-CSDN博客讲PC寄存器的时候有说过,忘记的小伙伴回头再看一下,那为什么GC的时候不使用多线程执行呢?也就是一遍GC一遍执行用户线程?看过六篇和七篇的小伙伴应该知道,最主要的原因是可达性分析算法需要在一个统一的系统快照进行标记,也就是必须暂停,不然用户线程一遍修改或者调用对象,那可达性分析就可能标记错误。

安全点和安全区

这两个概念大家应该都没听说过,这个是保证JVM能够安全的执行GC的机制,大家都知道执行GC的时候会触发STW线程暂停,但是不是说暂停就马上暂停的,比如一个线程正在删除或者新建对象的途中突然暂停可能会导致内存的损坏,所有呢,在执行GC之前应该先让线程达到安全暂停的区域,保证不会出现问题再暂停执行GC。而安全点呢可以理解为一个检查点比如在方法调用啊、循环结束啊、异常抛出啊等安全的时间点,进行检查满足条件就暂停等待GC完成。

而安全区呢就是一个安全区域,在这个安全的区域不会收到检查,只要不出这个区域就不用暂停,出了这个区域就要进行检查了,在一些线程阻塞的情况使用,因为他们无法到达安全点进行检查了。

那有小伙伴问,GC是要暂停所有线程然后再执行的,也就是要等待所有线程到达安全点或者安全区才能执行GC,会不会住?这个是不会的,一方面是GC有一个等待时间,超过了就不会等待了,会强制中断这个线程,可能会抛出异常,但是GC也没办法,别人也是为了工作不是吗。

强引用、软引用、弱引用、虚引用

强引用:这个是我们最常用的方式,也就是我们使用new关键词创建的对象,或者把一个对象复制给另一个变量,简单来说就是我们日常使用的基本上都是强引用,特点就是只要这个对象还可达那就不会被回收,即使内存不足了。

软引用:这个就有点复杂了,看下面的代码,一句话总结就是软引用会在内存不足的时候被回收,内存充足的情况下是不会管的。软引用的使用场景一般都是图片缓存啊这种。

//第一种
Object o = new Object();                      // 强引用
SoftReference softRef = new SoftReference(o); // 软引用
o = null;  // 断开强引用

// 第二种
SoftReference softRef = new SoftReference(new Object());
// 获取对象(可能返回 null)
Object obj = softRef.get();

首先看第一种,我们都知道o其实就是个强引用,然后使用new SoftReference创建一个对象,声明软引用o,这其实是比较矛盾的,因为他们其实都使用了new,所有o和softRef其实都是强引用的关系,如果不把o设为null那么o永远无法回收。

而第二种中的new Object就是一个软引用,引用这个Object对象,softRef.get()指向的就是这个Object对象,如果这个时候内存不足了,就会把这个Object对象回收,所有get可能为空,但是重要的是SoftReference这个对象是不会被回收的,因为他是个强引用。

弱引用:就是不管内存够不够下一次GC的时候就会回收他,使用场景就是一些监听器,当一个监听器没有被强引用后会被自动回收。可能有同学会问这能有啥用啊,可能一个方法执行途中就被回收了。确实是这样,但是一些场景下还是十分有用的,比如我们定义的临时监听器,通常情况下我们都是交给Spring容器管理这个监听器,但就算没有被使用可能还是存活的,那么这个弱引用就可以帮我们回收这部分资源避免内存泄漏。但有一说一使用场景还是很少的,因为我觉得一个监听器的作用就是监听应该随着程序一起创建和消亡,当然咯肯定是有需要的场景的,不然也不会有弱引用出现。

虚引用:他的唯一作用就是 ​监控对象何时被垃圾回收,并在回收后执行清理操作(如释放堆外内存、关闭文件等)。这个功能是不是感觉很熟悉好像在哪里见过,没错这个和主包之前讲的finalize()方法的功能大致是一样的,区别就是虚引用是在被回收后执行,finalize是在被回收前执行,下面看一下伪代码了解一下吧。

        // 1. 创建引用队列(用于接收被回收的对象)
        ReferenceQueue queue = new ReferenceQueue();

        // 2. 创建目标对象(需监控回收的对象)
        Object target = new Object();

        // 3. 创建虚引用,并关联引用队列
        PhantomReference phantomRef = new PhantomReference(target, queue);

        // 4. 断开强引用,让对象可被回收
        target = null;

        // 5. 触发 GC(仅用于演示,生产环境不推荐强制 GC)
        System.gc();

        // 6. 检查引用队列,确认对象是否被回收
        //    (此处会阻塞,直到虚引用入队)
        PhantomReference> ref = (PhantomReference>) queue.remove();
        if (ref == phantomRef) {
            System.out.println("对象已被回收,执行清理操作");
            // 这里可以释放资源(如关闭文件、释放堆外内存等)
        }

要注意的是使用虚引用必须搭配引用队列使用,不然就是无效的,队列会一直阻塞直到有对象被回收才会入队,才能执行下一步操作,而且ReferenceQueue不止可以是虚引用也可以是其他引用类型哦。

终结器引用(FinalReference)

这里说到了finalize那就说一下这个终结器吧,终结器引用是 Java 中与 finalize() 方法关联的特殊引用类型,属于 JVM 内部机制(未直接暴露给开发者)。它的核心作用是 ​管理需要执行 finalize() 的对象,是 JVM 实现对象终结(finalization)的关键组件。意思就是当一个对象要被回收了,而且重写了finalize方法那么就会加入FinalizerQueue队列,然后执行finalize方法。这个引用类型只适用于finalize方法,而且是一个对立的线程,会或多或少影响程序的吞吐量。

总结

本篇的内容是对JVM的一下扩展知识,为了跟好的帮助大家理解。好了就这下篇见。

文章来源于互联网:JVM学习日记(八)Day8

相关推荐: laravel RedisException: Connection refused优雅草PMS项目管理系统报错解决-以及Redis 详细指南-优雅草卓伊凡

laravel RedisException: Connection refused优雅草PMS项目管理系统报错解决-以及Redis 详细指南-优雅草卓伊凡 今天来开始更新pms系统,因为我们ppt上面要做,才发现原来打不开,此前主要是事情太多,我们一直有很多…

赞(0)
未经允许不得转载:5bei.cn大模型教程网 » JVM学习日记(八)Day8
分享到: 更多 (0)

AI大模型,我们的未来

小欢软考联系我们