Java对象引用关系之软引用

0x00 前言

JDK 1.2后,Java一共存在四种引用关系,分别是强引用、软引用、弱引用和虚引用。其中强引用是最常见的引用,代表程序运行所必须存在的引用,而软引用是非必须品,通常用于本地缓存。

0x01 软引用概述

当我们在程序中使用A a = new A()时产生的就是一个强引用,强引用代表的程序的运行必须使用使用该对象,因此被强引用的对象不能被GC回收。而软引用不像强引用一样是必须品,当内存充足时,软引用会被保留,当内存紧张时,会优先回收无任何引用的对象,然后再考虑回收软引用。

在这里插入图片描述

0x02 软引用的使用

软引用需要被SoftReference对象包装,具体使用如下

SoftReference<A> sr = new SoftReference<>(new A());

上述代码中创建了一个A对象,但是没有创建A对象的强引用,而是创建了一个SoftReference对象对其进行软引用。具体的引用关系如下:
sr ——> SoftReference对象 ----> A对象
其中 ——> 代表强引用, ----> 代表软引用。

0x03 软引用的回收

软引用对象与其外围的SoftReference对象是一体的,当内存不足时软引用对象被回收后,其外围的SoftReference对象也同样应该被回收。
对于软引用的对象,它们会在内存不足时被GC自动回收,如果我们想要提前回收软引用对象,而不是等到内存不足时再回收,那么就可以考虑将SoftReference对象置为null,这样做删除了SoftReference的强引用,根据可达性分析,软引用对象同样需要被回收。代码示例如下:

public class MySoftReference {

    public static void printMemoryUsage() {
        long totalMemory = Runtime.getRuntime().totalMemory() >> 20;
        long freeMemory = Runtime.getRuntime().freeMemory() >> 20;
        long usedMemory = totalMemory - freeMemory;
        System.out.println("Total Memory: " + totalMemory + " Mbytes");
        System.out.println("Used Memory: " + usedMemory + " Mbytes");
    }
    public static void main(String[] args) throws IOException {
        byte[] data = new byte[100 << 20];
        printMemoryUsage();
        SoftReference<byte[]> sr = new SoftReference<>(data);
        data = null;
        sr = null;
        System.gc(); // request for GC
        printMemoryUsage();
    }
}

输出结果如下:

Total Memory: 192 Mbytes
Used Memory: 105 Mbytes
[GC (System.gc())  106545K->103376K(196608K), 0.0009059 secs]
[Full GC (System.gc())  103376K->641K(196608K), 0.0042565 secs]
Total Memory: 192 Mbytes
Used Memory: 1 Mbytes

注意这里我将JVM的堆内存上限改为了200MB,所以启动时只有192MB,当我们将sr置为null并且手动调用GC后,使用内存恢复到了1MB,说明软引用对象被回收。

除了直接将软引用对象置为null之外,Java也提供了另一种更加优雅的回收方式,当软引用对象被回收时,其外层的SoftReference对象会被放入到队列中,我们可以通过遍历队列来获取这些对象。代码示例如下,

ArrayList<SoftReference> softReferences = new ArrayList<>();
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for (int i = 0; i < 5; i++) {
    byte[] data = new byte[100 << 20];
    SoftReference<byte[]> reference = new SoftReference<>(data, queue);
    softReferences.add(reference);
}
SoftReference<byte[]> ref = null;
while ((ref = (SoftReference<byte[]>) queue.poll()) != null) {
    System.out.println(ref.get());
}

输出结果如下:

null
null
null
null
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值