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

java中的四种引用

在java中对象的引用有强、软、弱、虚四种,这些引用级别的区别主要体现在对象的生命周期、回收时机的不同。这里在已知结论的情况下对其进行验证。

准备工作

1. 设置内存

为方便调试,将内存设置为16MB

  1. 依次点击菜单栏的Run—>Edit Configurations

    在这里插入图片描述

  2. 点击 Modify options —> Add VM option
    在这里插入图片描述

  3. 添加参数
    我这里设置的内存是16m, 对应参数为 -Xms16m -Xmx16m
    在这里插入图片描述

2. 内存检测

使用 runtime.freeMemory() 的api,用来获取到未使用内存大小

强引用

这是最常见的引用,就是平时用的"=" 赋值,当将变量指向null时则表示去除了强引用,当触发gc时变量会被回收。

public static void main(String[] args) {
	Runtime runtime = Runtime.getRuntime();
	runtime.gc();
	System.out.println("创建数组前剩余内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
	byte[] bytes = new byte[10 * 1024 * 1024];
	System.out.println("创建数组后所用内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
	// 去除强引用
	bytes = null;
	System.gc();
	System.out.println("垃圾回收之后所用内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
}

打印结果:

创建数组前剩余内存:14.730506896972656MB
创建数组后所用内存:3.5946426391601562MB
垃圾回收之后所用内存:14.682281494140625MB

可以看出当变量bytes指向null后,调用gc将会回收byte数组。但当bytes=null后,就无法引导到byte数组。

软引用

软引用引用的变量在gc时不会被回收,只有在内存不足时才会被回收。

public static void main(String[] args) {
    Runtime runtime = Runtime.getRuntime();
    runtime.gc();
    System.out.println("创建数组前剩余内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
    byte[] bytes = new byte[10 * 1024 * 1024];
    System.out.println("创建数组后所用内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
    SoftReference<byte[]> softReference = new SoftReference<>(bytes);
    System.out.println("添加软引用后剩余内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
    bytes = null;
    System.out.println("弱引用的引用对象:" + softReference.get());
    System.gc();
    System.out.println("去除强引用后剩余内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
    System.out.println("弱引用的引用对象:" + softReference.get());
    // 创建一个大于剩余内存的数组
    byte[] bigBytes = new byte[(int) (runtime.freeMemory() + 1024)];
    System.out.println("弱引用的引用对象:" + softReference.get());
}

打印结果:

创建数组前剩余内存:14.630073547363281MB
创建数组后所用内存:3.5899581909179688MB
添加软引用后剩余内存:3.5699386596679688MB
软引用的引用对象:[B@5305068a
去除强引用后剩余内存:3.66766357421875MB
软引用的引用对象:[B@5305068a
软引用的引用对象:null

当bytes = null并且gc时,byte[]并没有被回收。但在bigBytes时,由于内存不足,jvm会对软引用的对象进行回收。

弱引用

    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();
        runtime.gc();
        System.out.println("创建数组前剩余内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
        byte[] bytes = new byte[10 * 1024 * 1024];
        System.out.println("创建数组后所用内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
        WeakReference<byte[]> weakReference = new WeakReference<>(bytes);
        System.out.println("添加弱引用后剩余内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
        bytes = null;
        System.out.println("弱引用的引用对象:" + weakReference.get());
        System.gc();
        System.out.println("弱引用的引用对象:" + weakReference.get());
    }
}

打印结果:

创建数组前剩余内存:14.629707336425781MB
创建数组后所用内存:3.5896987915039062MB
添加弱引用后剩余内存:3.5696792602539062MB
弱引用的引用对象:[B@5305068a
弱引用的引用对象:null

弱引用在gc触发后就会回收对象

虚引用

虚引用的创建与软引用、弱引用不同,它需要传入一个引用队列

    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();
        runtime.gc();
        System.out.println("创建数组前剩余内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
        byte[] bytes = new byte[10 * 1024 * 1024];
        System.out.println("创建数组后所用内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
        ReferenceQueue<byte[]> referenceQueue  = new ReferenceQueue<>();
        PhantomReference<byte[]> phantomReference = new PhantomReference<>(bytes, referenceQueue);
        bytes = null;
        new Thread(() -> {
            while (true) {
                PhantomReference<byte[]> poll = (PhantomReference<byte[]>) referenceQueue.poll();
                if (poll != null) {
                    System.out.println("虚引用对象被回收了");
                    break;
                }
            }
        }).start();
        System.out.println("gc前虚引用的引用对象:" + phantomReference.get());
        System.gc();
        System.out.println("gc后虚引用的引用对象:" + phantomReference.get());
    }

输出:

创建数组前剩余内存:14.629470825195312MB
创建数组后所用内存:3.5897750854492188MB
gc前虚引用的引用对象:null
gc后虚引用的引用对象:null
虚引用对象被回收了:java.lang.ref.PhantomReference@618defd6

不能通过虚引用去引用对象,在gc后可以在ReferenceQueue.poll()得到虚引用

总结

创建赋值nullgc内存不足gc
强引用使用
存活
软引用使用
存活
弱引用使用
存活
虚引用使用
存活

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

相关文章:

  • java数据类型之间的转换|超详解
  • 基于Java的旅游类小程序开发与优化
  • 【Node.js】使用 Node.js 需要了解多少 JavaScript?
  • Linux(CentOS)安装达梦数据库 dm8
  • Python酷库之旅-第三方库Pandas(221)
  • 【Oracle篇】掌握SQL Tuning Advisor优化工具:从工具使用到SQL优化的全方位指南(第六篇,总共七篇)
  • 【高分系列卫星简介——高分辨率多模综合成像卫星】
  • 无人机飞手入伍当兵技术优势分析
  • Android中使用RecyclerView制作横向轮播列表及索引点
  • 前端基础知识汇总(一)
  • 李宏毅机器学习2022-HW9--Explainable AI
  • 鸿蒙面试题库收集(一):ArkTSArkUI-基础理论
  • MySQL知识点复习 - 常用的日志类型
  • 浅谈Java之多线程锁处理
  • kali linux crunch工具使用 -- 生成字典
  • 【常见框架漏洞】ThinkPHP、struts2、Spring、Shiro
  • 【数据结构】堆(Heap)详解
  • 前端框架的选择与考量:一场技术的盛宴
  • [Doc][ROS2]订阅发布、服务客户端区别
  • django drf 自动注册路由
  • Leetcode尊享面试100题-252.会议室
  • 产品推介——SOP4 随机相位可控硅光耦KLM305X
  • Docker Init 实战详解:从入门到精通
  • 前端练习总结(1)
  • 选择、冒泡、插入排序
  • 【Redis 源码】2项目结构说明