你会使用软引用和弱引用吗?

这篇文章我们来聊聊软引用和弱引用对内存性能的帮助,大家在平时的开发过程中,对于内存性能做过哪些调优工作,其中的一个方法就是我们可以使用软引用和弱引用。

软引用和弱引用的定义

  • 软引用(SoftReference):

如果一个对象只具有软引用,而当前虚拟机堆内存空间足够时,那么垃圾回收器就不会回收它,反之就会回收当前软引用指向的对象。

  • 弱引用(WeakReference):

垃圾回收器发现一个对象上只有弱引用,此时不管内存够不够,这个对象都会被回收。

下面通过一段简单的代码来看一下软引用和弱引用的具体用法;

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class ReferenceDemo {
    public static void main(String[] args) {
        //强引用
        String str = new String("abc");
        //弱引用
        SoftReference softRef = new SoftReference<>(str);
        str = null; //去掉强引用
        System.gc();    //垃圾回收器进行回收
        System.out.println(softRef.get());

        //强引用
        String abc = new String("123");
        //弱引用
        WeakReference weakRef = new WeakReference<>(abc);
        abc = null; //去掉强引用
        System.gc();    //垃圾回收器进行垃圾回收
        System.out.println(weakRef.get());
    }
}

通过上面这个例子,我们来分析一下软引用和弱引用的差别,首先看弱引用的例子,我们先定义了一个强引用对象,然后我们给这个强引用对象加了一个软引用,这里要注意软引用的写法是SoftReference,然后我们通过str = null来去掉str对象的强引用,此时str这个对象只有一个软引用,通过System.gc();我们进行了一次垃圾回收,因为str这个对象只有一个弱引用,没有强引用,而这是内存足够,所以说这个对象是不会被垃圾回收器回收的,它的输出是abc。

然后我们看第二个例子,首先定义了一个强引用对象,然后给这个对象加了一个弱引用,这里给对象加弱引用的方法是WeakReference,我们再通过abc = null,去掉这个对象的强引用,此时abc这个对象就只有一个弱引用,通过System.gc()进行了一次垃圾回收,这个适合abc这个对象没有强引用,只有一个弱引用,根据弱引用的定义,在垃圾回收之后,这个对象会被回收的,所以说弱引用的输出结果是null。

那么最终的结果是不少我们分析的这样,我们run一下看看,如下图所示,只有弱引用的对象在内存空间足够的时候没有被回收,对象在只有弱引用的时候被垃圾回收器回收。

软引用的使用场景:

比如说在一个博客管理系统里,为了提升访问性能,用户在点击博文时,如果这篇博文有缓存,这样其他用户在点击这篇博文时,就直接从内存中加载,而不走数据库,而这样可以降低响应时间,首先,我们定义一个Content类,来封装博文的内容,

然后我们定义一个类型为HashMap>对象来保存缓存内容,其中键是String类型表示文章id,值是一个指向Content的软连接,随后当用户点击某个id时,用id去HashMap中找,如果找到,并且Content的内容不为空,那么从中拿数据并直接做展示动作,这样的话,不要查询数据库,可以提高性能。在其中用id找不到,或者虽然找到,但是其中内容为空,那么我们就从数据库里面去找,找到文章后同时把它插入到HashMap这个缓存中,这个地方要注意,插入缓存后要删除Content上的强引用,从而保证只有一个软引用。

这样用软引用的好处,假设我们用1GB的内存,缓存了10000篇博文,那么这10000篇博文,在内存空间上只有软引用,没有强引用,如果内存空间足够时,那么我们可以通过缓存来提升性能,但是万一内存不够,我们可以依次释放这10000篇博文占用的内存,而释放时不会影响业务流程,最多就是稍微影响性能。

对比一下,如果这里我们用强引用来做缓存,会有什么后果,由于我们不知道什么时候该撤销在Content上的强引用,所以说找不到一个合适的机会来释放缓存。如果我们再引入一套缓存机制,这就属于额外工作了,就没有像软引用这样直接了。

弱引用的使用场景:

在某个电商网站中,我们会用Coupon类来保存优惠券信息,比如我们其中可以定义优惠券打折程度,有效期和作用范围等等,当我们从数据库中,得到所有的优惠券信息之后,会用一个List类型来保存优惠券,这个时候,如果我们想保存优惠券和它关联的用户时,我们可以用WeakHashMap>>这样类型的weakCouponHM对象,这样的对象,它主体是WeakHashMap,也就是基于弱引用的HashMap,其中键是Coupon类型,值是指向List>的弱引用,想象一下,如果有一百个优惠券,那么它会存储在List类型中的couponList中,同时在WeakHashMap这个类型对象里,也会用键的形式存储这100个优惠券。加入有10000个用户,我们可以用List类型的userList对象来保存它们。

我们假设coupon1这个优惠券对应100个用户,那么我们可以通过weakCouponHM.put()方法来添加它们的对于关系,其中是以弱引用的方法, 保存了coupon1所对应的100个用户,同理,当假设某个优惠券3,用弱引用的方式指向这100个用户,当某个用户注销账户时,它会从List这个对象中删除,换句话说,这个对象就只有在weakCouponHM里面的值,也就是只有一个弱引用,在下次垃圾回收的时候回被清除,这样coupon3上关联的用户它会被自动更新成99个。

相比之下,我们不用弱引用而选择用强引用,那么我们就在用户被删除之后,需要手动删除用户和优惠券之间的对应关系,如果忘了删除就会出现代码问题,相比之下,当我们引用弱引用时,就会给我们带来“自动更新”这样的好处。

更多Java相关文章、资料,可以关注公众号故里学Java,回复资源包获取

你可能感兴趣的:(你会使用软引用和弱引用吗?)