一文讲透java弱引用以及使用场景

概念

大部分情况下我们看到是强引用,比如下面这一行:

String str1 = new String("abc");

变量str1被用来存放一个string对象的强引用上。强引用在你正在使用时这个对象时,一般是不会被垃圾回收器回收的。当出现内存空间不足时,虚拟机不会释放强引用的对象占用的空间,而是选择抛出异常(OOM)。

什么时候会回收强引用的空间呢,就是没有引用的时候,比如你这样写:

str1 = null

GC在适当的时候就会回收str1指向的空间。

而弱引用(Weak Reference)的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

java中使用弱引用的语法是:

String str1 = new String("abc");
WeakReference<String> weakReference = new WeakReference<>(str1);

深入原理

我们先来通过一个案例,看下gc对于弱引用的回收策略。

import java.lang.ref.WeakReference;

public class WeakReferenceTest {
    public static WeakReference<String> weakReference1;
    public static WeakReference<String> weakReference2;
    public static void main(String[] args) {

        test1();
        //test1外部,hello对象作用域结束,没有强引用指向"value"了。只有一个弱引用指向"value"
        System.out.println("未进行gc时,只有弱引用指向value内存区域 weakReference1:" + weakReference1.get());

        //此时gc时会回收弱引用
        System.gc();

        //此时输出都为nuill
        System.out.println("进行gc时,只有弱引用指向value内存区域 weakReference1:" + weakReference1.get());

    }

    public static void test1() {
        //hello对象强引用"value"
        String hello = new String("value");

        //weakReference1对象弱引用指向"value"
        weakReference1 = new WeakReference<>(hello);
        weakReference2= new WeakReference<>(new String("value2"));

        //在test1内部调用gc,此时gc不会回收弱引用,因为hello对象强引用"value"
        System.gc();
        System.out.println("进行gc时,强引用与弱引用同时指向value内存区域 weakReference1:" + weakReference1.get());
        System.out.println("进行gc时,强引用与弱引用同时指向value内存区域 weakReference2:" + weakReference2.get());
    }

运行的结果:


进行gc时,强引用与弱引用同时指向value内存区域 weakReference1:value
进行gc时,强引用与弱引用同时指向value内存区域 weakReference2:null
未进行gc时,只有弱引用指向value内存区域 weakReference1:value
进行gc时,只有弱引用指向value内存区域 weakReference1:null

这里有个前置知识说下,当要获得WeakReference的object时, 首先需要判断它是否已经被GC回收,若被收回,则下列返回值为空:

weakReference1.get();

根据这个结果,我们可以得出这样的结论:

  • 当有强引用指向value内存区域时,即使进行gc,弱引用也不会被释放,对象空间不回被回收。

    test1()方法内,虽然执行了gc,但是String hello变量 和weakReference1都指向 new String(“value”);对象,特别是String hello变量是局部变量,当 test1()执行完后才会销毁,此时尚未销毁,那么没有必要回收weakReference1,为什么?

    答案很简单,我们的若引用初衷是断开弱引用,让gc时 root发现 new String(“value”);是光杆司令,符合回收条件,当String hello变量仍然存在时,并不符合光杆司令,那么此时若断开,也无效,反而不如啥也不干!

    如果改造为:weakReference1 = new WeakReference<>( new String("value")); 就能立即生效,因为只有weakReference2唯一引用新建的string对象

  • 当无强引用指向value内存区域是,进行gc,弱引用会被释放,对象空间将会执行回收流程。

参考

一文讲透java弱引用以及使用场景

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值