JVM的Reference机制

1.finalizer生产大于消费导致内存溢出测试

User重写了finalize方法的类在创建User对象的同时会创建一个Finalizer对象并加入到Finalizer中以unfinalized为头节点的链表中,当触发GC时如果垃圾收集器判断User对象没有与GCRoot的强引用时则会将Finalizer放到Reference.pending属性上,由线程ReferenceHandler负责处理将Finalizer添加到Finalizer.queue中,然后由线程FinalizerThread负责处理,将Finalizer从Finalizer中以unfinalized为头节点的链表中移除,且调用Finalizer.queue.remove()将Finalizer从Finalizer.queue中移除再执行User中重写的finalize方法再讲Finalizer中的referent属性置空与User切断引用。
此时:
User对象:没有任何引用;
User对应的Finalizer对象:没有任何引用,其各个属性为 next(Finalizer)=this;prev=this;referent=null;queue=ReferenceQueue.NULL;next(Reference)=this; discovered=null;
需要再次触发GC才会回收Finalizer对象和User对象,如果没有触发新的GC则Finalizer对象和User对象会一直存在堆上。

2.WeakReference回收测试(关注pending状态时机)

使用WeakReference添加User引用,当触发GC时如果垃圾收集器判断User对象没有与GCRoot的强引用时将WeakReference放到Reference.pending属性上(此时WeakReference中的referent属性即User已经被回收掉了),由线程ReferenceHandler负责处理将WeakReference添加到创建WeakReference时传入的queue里。由于WeakReference对象本身还没有被回收切被queue强引用着,所以需要手动遍历queue切断WeakReference的强引用(WeakHashMap的原理)。

3.SoftReference回收测试(关注pending状态时机)

使用SoftReference添加User引用,当触发GC时如果垃圾收集器判断User对象没有与GCRoot的强引用,且JVM内存不足时(必须进行fullGC)将SoftReference放到Reference.pending属性上(此时SoftReference中的referent属性即User已经被回收掉了),由线程ReferenceHandler负责处理将SoftReference添加到创建SoftReference时传入的queue里。由于SoftReference对象本身还没有被回收切被queue强引用着,所以需要手动遍历queue切断SoftReference的强引用。

4.WeakReference和finalizer组合测试

当User重写了finalize方法其使用WeakReference添加了User的引用,当User在外部再无强引用时,垃圾回收器会将WeakReference(垃圾回收器将referent置空)和Finalizer放到Reference.pending(WeakReference和Finalizer的处理顺序无法保证,是由垃圾回收器决定的,不同垃圾回收器可能不一致)属性上,由ReferenceHandler进行处理,后续过程与1、2一致;

5.PhantomReference虚引用回收测试(关注pending状态时机和Cleaner测试)

// TODO待补充

Reference中存在Active/活跃状态、Pending/等待状态、Enqueued/已入列状态(排队状态)、Inactive/不活跃状态四种状态

Active

当Reference对象刚刚被创建且没有发生GCROOT检查时。
此时Reference各个属性状态:
referent=User对象
queue=创建Reference时传入的ReferenceQueue,未传入为ReferenceQueue.NULL
next=null
discovered=null
static pending=null

Pending

当触发可达性分析对对象进行GCRoot检测时,垃圾回收器会关注全部的Reference对象将referent属性GCRoot状态发生变化(不同的引用类型定义不同)的Reference放到一个队列A里,垃圾回收器遍历队列对Reference进行指定操作(不同的引用类型定义不同),并把Reference实例放置到Reference.pending属性上(静态),将队列中的下一个Reference实例放到当前Reference的discovered属性上,next赋值为this。

referent属性GCRoot状态发生变化(不同的引用类型定义不同):WeakReference和PhantomReference和FinalReference是referent没有强引用时;SoftReference是referent没有强引用且内存不足时。

指定操作(不同的引用类型定义不同):WeakReference和SoftReference和PhantomReference 将referent置为null并回收User;FinalReference不做特殊处理。

此时Reference各个属性状态:
referent= WeakReference和SoftReference和PhantomReference时referent=null;FinalReference时referent=User;
queue=创建Reference时传入的ReferenceQueue,未传入为ReferenceQueue.NULL
next=this/A[x]
discovered=A[x].next;
static pending=A[x]

Enqueued

Reference中有一个ReferenceHandler线程负责异步处理垃圾处理器放到Reference.pending上的Reference实例,如果这个Reference在创建时有传入ReferenceQueue即Reference.queue!=ReferenceQueue.NULL则将Reference实例添加到创建时传入的ReferenceQueue中。
此时Reference各个属性状态:
referent= WeakReference和SoftReference和PhantomReference时referent=null;FinalReference时referent=User;
queue=ReferenceQueue.ENQUEUED
next=上一个添加到创建时传入的ReferenceQueue中的Reference实例
discovered=null;
static pending=this.discovered;

Inactive

当调用创建Reference时传入的ReferenceQueue的poll()或者remove()方法时(一般定时调用ReferenceQueue的poll方法获取Enqueued状态的Reference来做对应处理),Reference会变为Inactive状态;即意味着此引用对象可以被回收,并且对内部封装的对象也可以被回收掉了。
此时Reference的各个属性状态:
referent= WeakReference和SoftReference和PhantomReference时referent=null;FinalReference时referent=null(Finalizer线程会显式置空referent);
queue=ReferenceQueue.NULL
next=this;
discovered=null;
static pending=此属性为静态属性可能受其他Reference和垃圾回收器影响变化。

JVM的Reference中的queue和pending等属性以及四种状态机制主要目的是用于JVM垃圾回收器线程和用户线程之间的通信,要知道线程通信的两种手段是共享内存和消息传递,JVM线程明显不能给用户线程发送消息,所以这是一种共享内存机制。JVM的垃圾回收器线程会操作pending属性将referent属性GCRoot状态发生变化的Reference实例放到pending属性上,在java中有一个线程ReferenceHandler对pending属性进行轮询监控处理放入queue中,然后用户线程可以通过变量queue获取到GC线程的通知。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

躺平程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值