java的四种引用类型

一、强引用

String s = "kkk";

s属于强引用,只要s属于根可达对象,则就算内存溢出,gc也不会回收

二、软应用

gc正常不会回收,除非内存不够用则会回收,多用于缓存机制场景;可单独开启线程监控引用队列,防止无效的软引用浪费内存;

可通过vm配置演示下面代码示例

-Xms4m -Xmx4m -XX:+PrintGC

public class TestSoftReferance {
    private static final List<Object> TEST_DATA = new LinkedList<>();
    public static void main(String[] args) throws InterruptedException {
        String s = new String("kkk");
        ReferenceQueue<String> q = new ReferenceQueue<String>();//指定引用队列
        SoftReference<String> reference = new SoftReference<String>(s,q);
        s = null;//去掉强引用,使得字符串对象只剩下软引用
        System.out.println(reference.get());//输出kkk

        // 该线程不断读取这个虚引用,并不断往列表里插入数据,以促使系统早点进行GC
        new Thread(() -> {
            for (int i=1;;i++) {
                System.out.println("===="+i+"===");
                TEST_DATA.add(new byte[1024 * 200]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
            }
        }).start();
        // 这个线程不断读取引用队列,当弱引用指向的对象呗回收时,该引用就会被加入到引用队列中
        new Thread(() -> {
            while (true) {
                Reference<? extends String> poll = q.poll();
                if (poll != null) {
                    System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);//打印弱引用对象
                    System.out.println("--- 回收对象 ---- " + poll.get());//既然都已经被回收了,这里自然get不到了
                }
            }
        }).start();

        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

执行结果:

可以看出是内存快不够用的时候才被回收掉的

三、弱引用

gc回收的时候,如果发现了则会回收,主要在于发现与否。

public class TestWeakReference {
    private static final List<Object> TEST_DATA = new LinkedList<>();
    public static void main(String[] args) throws InterruptedException {
        String s = new String("kkk");
        String s1 = new String("kkk");
        ReferenceQueue<String> q = new ReferenceQueue<String>();//指定引用队列
        WeakReference<String> reference = new WeakReference<String>(s,q);
        WeakReference<String> reference2 = new WeakReference<String>(s1,q);
        s = null;//去掉强引用,使得字符串对象只剩下弱引用
        s1 = null;//去掉强引用,使得字符串对象只剩下弱引用
        System.out.println(reference.get());//输出kkk
        // 该线程不断读取这个虚引用,并不断往列表里插入数据,以促使系统早点进行GC
        new Thread(() -> {
            for (int i=1;;i++) {
                System.out.println("===="+i+"===");
                TEST_DATA.add(new byte[1024 * 200]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
            }
        }).start();
        // 这个线程不断读取引用队列,当弱引用指向的对象呗回收时,该引用就会被加入到引用队列中
        new Thread(() -> {
            while (true) {
                Reference<? extends String> poll = q.poll();
                if (poll != null) {
                    System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);//打印弱引用对象
                    System.out.println("--- 回收对象 ---- " + poll.get());//既然都已经被回收了,这里自然get不到了,所以打印null
                }
            }
        }).start();

        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.exit(1);
        }


    }
}

 

执行结果:

可以看出第3次GC的时候就被发现并回收了

 四、虚引用

当试图通过虚引用的get()方法取得强引用时,总是会返回null,并且,虚引用必须和引用队列一起使用。既然这么虚,那么它出现的意义何在??

每次gc肯定都会回收,会被gc当做正常垃圾处理;可以通过引用队列追踪垃圾回收的时间和频率。

public class TestPhantomReference {
    private static final List<Object> TEST_DATA = new LinkedList<>();
    public static void main(String[] args) throws InterruptedException {
        String obj = new String("kkk");//注意:这里如果换成String obj = "kkk";则不会被gc回收,因为该对象存在常量池中;
        ReferenceQueue<String> q = new ReferenceQueue<String>();//指定引用队列
        PhantomReference<String> reference = new PhantomReference<String>(obj,q);
        obj = null;//去掉强引用,使得字符串对象只剩下虚引用
        System.out.println(reference.get());//输出null
        // 该线程不断读取这个虚引用,并不断往列表里插入数据,以促使系统早点进行GC
        new Thread(() -> {
            for (int i=1;;i++) {
                System.out.println("===="+i+"===");
                TEST_DATA.add(new byte[1024 * 200]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                }
            }
        }).start();

        // 这个线程不断读取引用队列,当弱引用指向的对象呗回收时,该引用就会被加入到引用队列中
        new Thread(() -> {
            while (true) {
                Reference<? extends String> poll = q.poll();
                if (poll != null) {
                    System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);
                    System.out.println("--- 回收对象 ---- " + poll.get());//既然都已经被回收了,这里自然get不到了
                }
            }
        }).start();

        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.exit(1);
        }

    }
}

运行结果如下:

第1次YGC的时候就给回收掉了

 五、引用队列概念:

除强引用外的引用如果失去引用的对象,则引用本身会进入引用队列;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无声游子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值