Reference和Reference Queue

起因

看guaua cache的时候看到源码里面有用到softReference、weakReference等作为key和value,突然想要深入理解一下引用的原理,看了源码和不少文章,终于有点感觉了,主要是gc控制了一些参数的设置,所以感觉有点难理解。关于基本的知识,我就不赘述了,反正我也是看的大家的文章?

源码和流程

大部分网上的文章都是差不多贴的源码注释:

/* A Reference instance is in one of four possible internal states:
     *
     *     Active: Subject to special treatment by the garbage collector.  Some
     *     time after the collector detects that the reachability of the
     *     referent has changed to the appropriate state, it changes the
     *     instance's state to either Pending or Inactive, depending upon
     *     whether or not the instance was registered with a queue when it was
     *     created.  In the former case it also adds the instance to the
     *     pending-Reference list.  Newly-created instances are Active.
     *
     *     Pending: An element of the pending-Reference list, waiting to be
     *     enqueued by the Reference-handler thread.  Unregistered instances
     *     are never in this state.
     *
     *     Enqueued: An element of the queue with which the instance was
     *     registered when it was created.  When an instance is removed from
     *     its ReferenceQueue, it is made Inactive.  Unregistered instances are
     *     never in this state.
     *
     *     Inactive: Nothing more to do.  Once an instance becomes Inactive its
     *     state will never change again.
     *
     * The state is encoded in the queue and next fields as follows:
     *
     *     Active: queue = ReferenceQueue with which instance is registered, or
     *     ReferenceQueue.NULL if it was not registered with a queue; next =
     *     null.
     *
     *     Pending: queue = ReferenceQueue with which instance is registered;
     *     next = this
     *
     *     Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
     *     in queue, or this if at end of list.
     *
     *     Inactive: queue = ReferenceQueue.NULL; next = this.
     *
     * With this scheme the collector need only examine the next field in order
     * to determine whether a Reference instance requires special treatment: If
     * the next field is null then the instance is active; if it is non-null,
     * then the collector should treat the instance normally.
     *
     * To ensure that a concurrent collector can discover active Reference
     * objects without interfering with application threads that may apply
     * the enqueue() method to those objects, collectors should link
     * discovered objects through the discovered field. The discovered
     * field is also used for linking Reference objects in the pending list.
     */

注释讲的算比较清楚了,虽然是英文,大家应该可以看懂啦!有个概念就行。网上有个状态转换图,比较清晰:
在这里插入图片描述
在这里插入图片描述
上面的图大概描述了一个对象从创建被回收的过程,看了这些好像有点了解了,但是还是有点蒙,我们再看看Reference的成员变量:

referent:被封装的对象
queue:注册的引用队列,只有注册了队列的Reference,才会有pending和enqueued的状态,引用队列的使用可以让我们知道对象什么时候被gc,gc的时候引用会被enqueue到队列里面,我们可以从队列中取出来,或者做一些监控(资源清除等),没有注册队列的reference,我们就一脸懵逼了。
next:在引用队列里面形成一个链表,也就是指向下一个被gc的引用对象,既然next指向引用队列的gc对象,那注释里面说”next != null,说明就是被gc了,收集器应该处理掉他了”就不难理解了。
discovered:这个我觉得是待加入到引用队列里面的一个对象,JVM帮我们设置的,和pending对象联合使用形成一个链表,相当于pending队列的next吧。
pending:static类型的,说明只有一个,也就是pending链表的head了。
ReferenceHandler:一个Thead,而且在static初始化代码里面设置了Thread.MAX_PRIORITY最高优先级,run方法里面就是个死循环

public void run() {
            while (true) {
                tryHandlePending(true);
            }
       }

tryHandlePending这个方法里面主要就是不断取出pending列表里面的引用,并且加入到ReferenceQueue里面去,也就是上图中从pending队列放到了ReferenceQueue队列中了。

reference里面的pending队列和referenceQueue队列都有lock进行控制,不会出现并发问题。

分析完成员变量,不知道大家理解一点了没有,我的表达水平有限,所以想多写写,练练手?。上面两张图还是画的很清楚的?,大家可以结合源码再看看,有什么问题可以交流,帮助我打怪升级。

具体的引用
软引用和弱引用:

软引用是在内存不足的情况下进行回收,那什么时候算内存不足呢?具体的jvm源码也不贴了,大致的计算方式就是:

interval > get_heap_free_at_last_gc * SoftRefLRUPolicyMSPerMB

SoftRefLRUPolicyMSPerMB:每1M空闲空间可保持的SoftReference对象生存的时长(单位毫秒),默认值是1000

interval= timestamp - clock(软引用的两个变量)

意思就是当这个引用被get(访问)的时间足够长,就可以被回收了,而get_heap_free_at_last_gc越大(内存越大,越不会内存不足),或者SoftRefLRUPolicyMSPerMB越大,软引用存活的时间就越长。

软引用会有一定的问题,由于要在内存不足的时候被回收,那如果一直不回收,就会被放到老年代,而老年代会越来越大,导致不停地full gc。

相对软引用,弱引用用的就比较多了,只要gc就会被回收,对JVM没有副作用,对于一般的缓存还挺有效的。

幻引用主要的实现就是Cleaner了,实现资源的回收和释放。

今天就这样了。以后有新发现再说。

参考:

https://www.jianshu.com/p/439a8f738153
https://coldwalker.com/2019/02//gc_intro/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值