当前位置: 首页 > article >正文

java的强,软,弱,虚引用介绍以及应用

写在前面

本文看下Java的强,软,弱,虚引用相关内容。

1:各种引用介绍

顶层类是java.lang.ref.Reference,注意是一个抽象类,而不是接口,其中比较重要的引用队列ReferenceQueue就在该类中定义,子类们共同使用:

// java.lang.ref.Reference
public abstract class Reference<T> {
    // ...
    volatile ReferenceQueue<? super T> queue;
    // ...
}

另,以下测试案例使用的gc配置:

-Xms10m -Xmx10m -XX:+PrintGC

1.1:强引用

平时我们用的默认就是强引用。所以也就没有一个类似于StrongReference的类来代表强引用了。

1.2:软引用

使用类SoftReference代表一个软引用,比强引用稍微弱化些,在内存空间充足时发生GC不会被回收,但是在内存不足发生GC时将会被回收,所以适合用在类似于缓存这种并不会对程序起到决定性作用的场景中。如下例子:

public void softRefTest() {
    /**
     *
     * @author mikechen
     */
    Object obj = new Object();
    SoftReference softRef = new SoftReference<Object>(obj);
    obj = null;//删除强引用

    byte[] b = new byte[1024 * 1024];
    System.gc();//调用gc
    System.out.println("gc之后的值:" + softRef.get()); // 对象依然存在
}

运行:

[GC (System.gc())  2663K->1713K(9728K), 0.0011382 secs]
[Full GC (System.gc())  1713K->1647K(9728K), 0.0055792 secs]
gc之后的值:java.lang.Object@330bedb4

Process finished with exit code 0

这里内存不足的场景我没有试出来,要么就OOM了。

软引用也可以选择和ReferenceQueue来一起使用,当软应用关联的对象被GC之后就会将软引用本身添加到队列中,如下:

public void softRefWithQueue() throws Exception {
    ReferenceQueue<Object> queue = new ReferenceQueue<>();
    Object obj = new Object();
    SoftReference softRef = new SoftReference<Object>(obj, queue);//删除强引用
    obj = null;
    //调用gc
    System.gc();
    System.out.println("gc之后的值: " + softRef.get()); // 对象依然存在,虽然GC但内存足够,不会回收
    //申请较大内存使内存空间使用率达到阈值,强迫gc
    byte[] bytes = new byte[1024 * 1024 * 6];//如果obj被回收,则软引用会进入引用队列
    System.out.println("111");
    //调用gc
    System.gc();

    Reference<?> reference = queue.remove(); // 因为没有触发内存不足的场景,所以不会添加到队列中,所以这里会卡着
    System.out.println("222");
    if (reference != null) {
        System.out.println("对象已被回收: " + reference.get());// 对象为null
    }
}

运行:
在这里插入图片描述
同样试不出来内存不足被回收的场景。

1.3:弱引用

弱引用和软引用的区别是在发生GC时不管内存是否足够,都会被回收,看个例子:

    private void weakRef() {
    Object o1 = new Object();
    WeakReference<Object> w1 = new WeakReference<Object>(o1);

//        System.out.println(o1);
    System.out.println(w1.get()); // 因为此时还有强引用,肯定不会被回收

    o1 = null; // 手动去除强引用
    System.gc();

//        System.out.println(o1);
    System.out.println("因为发生了GC,所以就被回收掉了:");
    System.out.println(w1.get()); // 因为发生了GC,所以就被回收掉了
}

运行:

java.lang.Object@330bedb4
[GC (System.gc())  1570K->745K(9728K), 0.0010741 secs]
[Full GC (System.gc())  745K->622K(9728K), 0.0059361 secs]
因为发生了GC,所以就被回收掉了:
null

Process finished with exit code 0

当然也可以和ReferenceQueue一起使用,来监听对象被回收的动作:

private void weakRefWithQueueV1() throws Exception {
    CC o1 = new CC();
    o1.setName("张三");
    ReferenceQueue referenceQueue = new ReferenceQueue();
    Map<WeakReference, String> map = new HashMap<>();
    WeakReference<CC> w1 = new WeakReference<CC>(o1, referenceQueue);
    map.put(w1, w1.get().getName());
//    System.out.println(w1);
//
//    System.out.println(o1);
    System.out.println(w1.get()); // 因为此时还有强引用,肯定不会被回收

    o1 = null; // 手动去除强引用
    System.gc();

//        System.out.println(o1);
    System.out.println("因为发生了GC,所以就被回收掉了:");
    System.out.println(w1.get()); // 因为发生了GC,所以就被回收掉了

    final Reference ref = referenceQueue.remove();
    System.out.println(map.get(ref) + " 被回收了"); // 因为对象被回收,所以弱引用对象本身会被放到队列中
}

运行:

org.example.Main$CC@2503dbd3
[GC (System.gc())  1647K->709K(9728K), 0.0009438 secs]
[Full GC (System.gc())  709K->628K(9728K), 0.0058506 secs]
因为发生了GC,所以就被回收掉了:
null
张三 被回收了

Process finished with exit code 0

1.4:虚引用

虚引用是最弱的的一种引用,不决定对象的生命周期,有跟没有一样,即形同虚设,必须和ReferenceQueue共同使用,一般用来监控jvm的gc活动,如下例子:

private void weakPhantomWithQueueV1() throws Exception {
    CC o1 = new CC();
    o1.setName("张三1");
    ReferenceQueue referenceQueue = new ReferenceQueue();
    Map<PhantomReference, String> map = new HashMap<>();
    PhantomReference<CC> w1 = new PhantomReference<CC>(o1, referenceQueue);
    map.put(w1, o1.getName());
//        System.out.println(w1);

//        System.out.println(o1);
    System.out.println(w1.get()); // 因为此时还有强引用,肯定不会被回收

    o1 = null; // 手动去除强引用
    System.gc();

//        System.out.println(o1);
    System.out.println("因为发生了GC,所以就被回收掉了:");
    System.out.println(w1.get()); // 因为发生了GC,所以就被回收掉了

    final Reference ref = referenceQueue.remove();
    System.out.println(map.get(ref) + " 被回收了"); // 因为对象被回收,所以弱引用对象本身会被放到队列中
}

运行:

null
[GC (System.gc())  1643K->741K(9728K), 0.0012171 secs]
[Full GC (System.gc())  741K->627K(9728K), 0.0062680 secs]
因为发生了GC,所以就被回收掉了:
null
张三1 被回收了

Process finished with exit code 0

2:在框架中的应用

2.1:在netty中的应用

just go。

2.2:在mybatis中的应用

TODO

写在后面

参考文章列表

Java四大引用详解:强引用、软引用、弱引用、虚引用 。

netty之内存泄露检测。


http://www.kler.cn/a/406403.html

相关文章:

  • 移动语义和拷贝语义区别、智能指针
  • 【大数据分析机器学习】分布式机器学习
  • Redis密码设置与访问限制(网络安全)
  • 第6篇 寻找最大数___ARM C语言程序<二>
  • java-贪心算法
  • Spring Boot核心概念:日志管理
  • 提供一个集中式的数字媒体模板库,涵盖各类设计模板(如海报、视频片头、社交媒体帖子等),支持关键词、标签、风格等多维度搜索,帮助用户快速定位所需模板。
  • 【.ner core】 配置使用百度编辑器
  • JavaScript中的this指向问题
  • 容器安全检测和渗透测试工具
  • 成都栩熙酷,电商服务新选择
  • 【SQL Server】华中农业大学空间数据库实验报告 实验七 数据查询
  • 【大语言模型】ACL2024论文-13 透过分裂投票的镜头:探索法律案例结果分类中的分歧、难度和校准
  • “AI玩手机”原理揭秘:大模型驱动的移动端GUI智能体
  • 【Redis 探秘】Redis 持久化机制:RDB 与 AOF
  • 特征融合篇 | CARAFE:轻量级通用上采样算子,可提高目标检测性能
  • 设计模式在项目中有用过吗?怎么用的?
  • 数据结构 (3)线性表的概念及其抽象数据类型定义
  • go项目中比较好的实践方案
  • 【qt版本概述】
  • js前端加密方案库Crypto-js之aes的使用
  • 速通前端篇 —— CSS
  • c++中操作数据库的常用函数
  • 前端vue调试样式方法
  • 前端 px、rpx、em、rem、vh、vw计量单位的区别
  • 【D3.js in Action 3 精译_040】4.4 D3 弧形图的绘制方法