java中的强软弱虚

发布于:2024-10-09 ⋅ 阅读:(38) ⋅ 点赞:(0)

在这里插入图片描述
在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");
	System.gc();
	System.out.println("触发gc后所用内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
	// 去除引用关系
	bytes = null;
	System.gc();
	System.out.println("去除引用关系后所用内存:" + runtime.freeMemory() / 1024.0 / 1024 + "MB");
}

打印结果:

创建数组前剩余内存:14.630088806152344MB
创建数组后所用内存:3.5891189575195312MB
触发gc后所用内存:3.6717300415039062MB
去除引用关系后所用内存:14.680328369140625MB

可以看出存在强引用关系时,即便触发gc该对象也不会被垃圾回收器回收

软引用

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

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

打印结果:

创建数组前剩余内存:14.631034851074219MB
添加软引用后剩余内存:3.5826187133789062MB
弱引用的引用对象:[B@5305068a
触发gc后所用内存:3.668914794921875MB
弱引用的引用对象:[B@5305068a
弱引用的引用对象:null

使用软引用时,触发gc对象不会被垃圾回收器回收,但当内存不足时,对象会被gc回收

弱引用

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

打印结果:

创建数组前剩余内存:14.731277465820312MB
添加弱引用后剩余内存:3.5902481079101562MB
弱引用的引用对象:[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");
        ReferenceQueue<byte[]> referenceQueue  = new ReferenceQueue<>();
        PhantomReference<byte[]> phantomReference = new PhantomReference<>(new byte[10 * 1024 * 1024], referenceQueue);
        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.730300903320312MB
gc前虚引用的引用对象:null
虚引用对象被回收了
gc后虚引用的引用对象:null

不能通过虚引用去使用对象,主要用于跟踪对象被垃圾回收器回收的状态。