java 深入理解java引用

深入理解java引用

强引用
描述

强引用在java中普遍存在,类似Object object=new Object(),任何情况下,只要这种强引用一直存在,那么这个强引用对象就不会被垃圾收集器回收

软引用(SoftReference)
描述

软引用描述着一些还有用,非必须的对象,只要被软引用管理的对象,会在内存溢出之前,会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有获取足够的内存,才会报OOM异常,但是如果所关联对象如果被强引用所指向,那么就不会被回收,就算OOM。

内存不够用时,会回收软引用,除非软引用所关联对象 被强引用所指向 ,不会被垃圾回收,就算OOM,直到OOM.

代码示例1

证明内存不够用时,软引用所关联的对象会被回收。

//JVM参数设置  -Xmx1m 当内存不够用时
public static void test1() throws InterruptedException {
        byte[] bytes2=new byte[200*1024];
        SoftReference<byte[]> softReference= new SoftReference<>(new byte[500*1024]);
        System.out.println(softReference.get());
        System.gc();
        TimeUnit.SECONDS.sleep(2);
        System.out.println(softReference.get());
}
//JVM参数设置  -Xmx1m 当内存够用时
public static void test2() throws InterruptedException {
    SoftReference<byte[]> softReference= new SoftReference<>(new byte[1*1024]);
    System.out.println(softReference.get());
    System.gc();
    TimeUnit.SECONDS.sleep(2);
    System.out.println(softReference.get());
}

运行结果

test01执行结果

在这里插入图片描述

test02 执行结果

在这里插入图片描述

分析

当内存够用时,不会被回收,当内存不够用时,会被回收。

疑问

那如果被强引用所指向是,会被回收吗?直接报OOM?

public static void test3() throws InterruptedException {
        byte[] bytes2=new byte[200*1024];
        byte[] bytes3=new byte[500*1024];
        SoftReference<byte[]> softReference= new SoftReference<>(bytes3);
        System.out.println(softReference.get());
        System.gc();
        TimeUnit.SECONDS.sleep(2);
        System.out.println(softReference.get());
}

运行结果
在这里插入图片描述

猜想证实 ,直接报OOM

总结

1.软引用所关联的对象,当内存不够用即将发生OOM时,会清楚软引用所关联的对象。

2.当软引用所关联的对象被强引用所指向时,就算要OOM了,也不会去回收这个所关联的对象。

弱引用
描述

弱引用比软引用更甚,被弱引用关联的对象只能生存到垃圾收集回收开始,当垃圾回收器开始工作,那么垃圾回收器将会回收这一部分的对象。只要发生了GC,那么他就会被垃圾回收器所回收。

一般情况下只要发生了GC 那么就会被回收,除非被强引用所指向弱引用关联对象,那么不会被回收

代码示例1

被引用对象只能生存到垃圾回收器下一次垃圾收集开始

public static void test01() throws InterruptedException {
    WeakReference<Car> weakReference = new WeakReference<>(new Car());
    System.out.println(weakReference.get());
    System.gc();
    TimeUnit.SECONDS.sleep(2);
    System.out.println(weakReference.get());
}
static class Car {
}
运行结果

在这里插入图片描述

结论

被弱引用关联的对象 只能生存到垃圾回收器下一次垃圾收集开始

代码实例2
public static void test021() throws InterruptedException {
        WeakReference<Object> weakReference = new WeakReference<>(new Object());
        Object object = weakReference.get();
        System.out.println(object);
        System.gc();
        TimeUnit.SECONDS.sleep(2);
        Object object2 = weakReference.get();
        System.out.println(object2);
 }
运行结果

在这里插入图片描述

分析

对比代码实例2 有什么不同呢?为什么没有回收掉呢?

不同点:

1.实例2 中Object object 指向了 关联对象,意思是 在栈中分配了一个强引用指向弱引用所关联的对象

2 当垃圾回收,进行是否是垃圾判断,可达性分析时,由于Object 强引用指向了弱引用所关联的对象,此时认为该对象可达,所以没有进行回收。

那么如何让其被回收呢?上码

public static void test03() throws InterruptedException {
        WeakReference<Object> weakReference = new WeakReference<>(new Object());
        Object object = weakReference.get();
        System.out.println(object);
        object = null;
        System.gc();
        TimeUnit.SECONDS.sleep(2);
        Object object2 = weakReference.get();
        System.out.println(object2);
}

运行结果

在这里插入图片描述

分析

为什么将强引用置为空就能够被回收呢?

还是回到 上面的分析2 中,当垃圾回收器,进行垃圾回收判断时,此时的强引用已经被置为空,认为其不可达了,就和代码示例1是一样的了,所以判定为垃圾对象,所以进行了回收。

思考题:下面代码的运行结果

public static void test04() throws InterruptedException {
        Object objectF = new Object();
        WeakReference<Object> weakReference = new WeakReference<>(objectF);
        System.out.println(weakReference.get());
        objectF = null;
        System.gc();
        TimeUnit.SECONDS.sleep(2);
        Object object2 = weakReference.get();
        System.out.println(object2);
    }
总结

1.当弱引用所关联的对象,没有被强引用所指向时,弱引用所关联的对象只能存活到垃圾收集器开始收集时。

2.当弱引用所关联的对象,被强引用所指向时,弱引用所关联的对象是不能被垃圾收集器所回收的,因为在垃圾收集器做垃圾判定时,认为该所关联的对象被强引用所指向,所以认为是可达的。所以是不会被回收的。

虚引用
描述

他是最弱的一种引用,一个对象是否被虚引用关联,完全不会对其生命周期产生影响,并且通过虚引用获得关联对象永远是空。为一个对象设置虚引用关联完全是为了当这个对象被垃圾回收时,进行回调,收到一个通知而已。

示例代码
public static void test01() throws InterruptedException {
    ReferenceQueue<byte[]> referenceQueue=new ReferenceQueue<>();
    byte[] bytes2=new byte[200*1024];
    PhantomReference<byte[]> phantomReference= new PhantomReference<>(bytes2, referenceQueue);
    new Thread(()->{
        Reference ref;
        while((ref=referenceQueue.poll())==null){
        }
        System.out.println("dddd:"+ref);
    }).start();
    bytes2=null;
    TimeUnit.SECONDS.sleep(2);
    System.out.println("开始调用GC");
    System.gc();
    TimeUnit.SECONDS.sleep(2);
    System.out.println();
}
运行结果

在这里插入图片描述

分析

由此可看出 虚引用 的作用只是为了所关联的对象被垃圾回收器收集的时候,系统的回调通知而已。

总结

虚引用 是不能获取所关联的对象的,虚引用的作用就是获取所关联的对象被垃圾回收时,系统的回调。

总结

对于java引用,只要一个强引用所指向一个对象,并且这个强引用一直存在,那么就不会被垃圾回收器所回收

  1. 强引用
    只要这个强引用一直存在,那么就不会被垃圾回收器回收
  2. 软引用
    1. 软引用所关联的对象 一般生命止于 即将发生OOM时的那个时刻,当内存不够使用时,会被垃圾回收器所回收。
    2. 软引用所关联的对象 被强引用所指向时,并且这个强引用一直存在,那么被关联对象那么就不会被垃圾回收器所回收。
  3. 弱引用
    1. 弱引用所关联的对象 一般生命止与即将垃圾回收时,与软引用相比,不管内存够不够,弱引用所关联的对象都将会被回收。
    2. 弱引用所关联的对象 被强引用所指向时,并且这个强引用一直存在,那么被关联对象那么就不会被垃圾回收器所回收。
  4. 虚引用
    1. 不能够从虚引用中获取所关联的对象 源码默认null
      内存不够使用时,会被垃圾回收器所回收。
    2. 软引用所关联的对象 被强引用所指向时,并且这个强引用一直存在,那么被关联对象那么就不会被垃圾回收器所回收。
  5. 虚引用
    1. 不能够从虚引用中获取所关联的对象 源码默认null
    2. 虚引用完全不会影响所关联对象的生命周期,虚引用的作用完全是为了 当所关联的对象被垃圾回收器所回收时,收到系统的回调的通知。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值