前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你会使用软引用和弱引用吗?

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

作者头像
故里
发布2020-11-25 15:58:03
1K0
发布2020-11-25 15:58:03
举报
文章被收录于专栏:故里学Java故里学Java

戳这里,加关注哦~

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

软引用和弱引用的定义

  • 软引用(SoftReference):

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

  • 弱引用(WeakReference):

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

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

代码语言:javascript
复制
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<String> softRef = new SoftReference<>(str);
        str = null; //去掉强引用
        System.gc();    //垃圾回收器进行回收
        System.out.println(softRef.get());

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

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

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

弱引用的使用场景:

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

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-10-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 故里学Java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 软引用和弱引用的定义
  • 软引用的使用场景:
  • 弱引用的使用场景:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档