SoftReference软引用

示例代码:

import java.lang.ref.SoftReference;

/**
 * @author chenjc
 * @since 2020-01-13
 */
public class SoftReferenceTest {

    /**
     * 使用JVM参数-Xmx10m运行程序
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        User user = new User(1, "debo");
        // 建立User对象的软引用
        SoftReference<User> userSoftReference = new SoftReference<>(user);
        // 去掉强引用
        user = null;
        System.out.println(userSoftReference.get());
        // 手动触发GC
        System.gc();
        System.out.println("第一次GC: " + userSoftReference.get());
        // 分配适量内存空间,造成内存资源紧张,产生GC,同时又不会导致堆内存溢出
        byte[] bytes = new byte[6 * 1024 * 1050];
        System.out.println("第二次GC: " + userSoftReference.get());
    }

    private static class User {
        private Integer id;
        private String name;

        public User(Integer id, String name) {
            this.id = id;
            this.name = name;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
}

使用JVM参数-Xmx10m运行此程序,输出如下:

User{id=1, name='debo'}
第一次GC: User{id=1, name='debo'}
第二次GC: null

第一次GC的时候,软引用没有被回收,是因为这时候内存资源充足。第二次由于分配了较大的内存,导致GC,这时候由于内存资源紧张,软引用被回收了,也就是虽然User对象有一个软引用在引用着它,但User对象在此条件下也会被GC回收。所以软引用的对象在一定条件下可被回收,故软引用对象不会导致内存溢出。

软引用到底有没有被回收,可以通过给软引用一个ReferenceQueue来跟踪,将上面的代码片段稍作修改,如下:

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

/**
 * @author chenjc
 * @since 2020-01-13
 */
public class SoftReferenceTest {

    /**
     * 使用JVM参数-Xmx10m运行程序
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        User user = new User(1, "debo");
        // 建立User对象的软引用
        ReferenceQueue<User> userReferenceQueue = new ReferenceQueue<>();
        UserSoftReference userSoftReference = new UserSoftReference(user, userReferenceQueue);
        // 去掉强引用
        user = null;
        System.out.println(userSoftReference.get());
        // 手动触发GC
        System.gc();
        System.out.println("第一次GC: " + userSoftReference.get());
        System.out.println("第一次GC队列: " + userReferenceQueue.remove(1000));
        // 分配适量内存空间,造成内存资源紧张,产生GC,同时又不会导致堆内存溢出
        byte[] bytes = new byte[6 * 1024 * 1055];
        System.out.println("第二次GC: " + userSoftReference.get());
        Reference<? extends User> reference = userReferenceQueue.remove(1000);
        if (reference != null) {
            UserSoftReference userSoftReference1 = (UserSoftReference) reference;
            System.out.println("第二次GC队列: " + userSoftReference1.getId());
        }
    }

    private static class User {
        private Integer id;
        private String name;

        public User(Integer id, String name) {
            this.id = id;
            this.name = name;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    }

    private static class UserSoftReference extends SoftReference<User> {

        private Integer id;

        public UserSoftReference(User referent, ReferenceQueue<? super User> q) {
            super(referent, q);
            this.id = referent.id;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }
    }
}

输出如下:

User{id=1, name='debo'}
第一次GC: User{id=1, name='debo'}
第一次GC队列: null
第二次GC: null
第二次GC队列: 1

第一次GC没有回收软引用对象,所以ReferenceQueue为空,第二次GC回收了软引用对象,所以ReferenceQueue队列不为空,那为什么可以强转成UserSoftReference呢?是因为队列里面的reference就是方法局部变量userSoftReference。此处自定义一个UserSoftReference类主要是为了跟踪User对象的id,你无法跟踪User对象,因为User对象已经被回收了,如果调用reference.get(),将会返回null。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值