说明
以前学习各个引用类型的区别,最近在看一个JVM参数-XX:SoftRefLRUPolicyMSPerMB 对软引用有更深入的了解
源码
public class SoftReference<T> extends Reference<T> { /** * 由垃圾回收器负责更新的时间戳 */ static private long clock; /** * 在get方法调用时更新的时间戳,当虚拟机选择软引用进行清理时,可能会参考这个字段。 */ private long timestamp; public SoftReference(T referent) { super(referent); this.timestamp = clock; } public SoftReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); this.timestamp = clock; } /** * 返回引用指向的对象,如果referent已经被程序或者垃圾回收器清理,则返回null。 */ public T get() { T o = super.get(); if (o != null && this.timestamp != clock) this.timestamp = clock; return o; } }
软引用回收时机
软引用会在内存不足的时候进行回收,但是回收时并不会一次性全部回收,而是会使用一定的回收策略
1.没有强引用时回收
2.根据限制时间clock-timestamp<=heap空间内存*-XX:SoftRefLRUPolicyMSPerMB(默认1000) true为不回收 false为回收
注意源码可以看出get和初始化都会将timestamp更新成clock的值
淘汰策略处理源码
-XX:SoftRefLRUPolicyMSPerMB
就HotSpot虚拟机而言,常用的回收策略是基于当前堆大小的LRU策略(LRUCurrentHeapPolicy),会使用clock的值减去timestamp,得到的差值,就是这个软引用被闲置的时间,如果闲置足够长时间,就认为是可被回收的。
bool LRUCurrentHeapPolicy::should_clear_reference(oop p, jlong timestamp_clock) { jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p); assert(interval >= 0, "Sanity check"); if(interval <= _max_interval) { return false; } return true; }
_max_interval计算公式
void LRUCurrentHeapPolicy::setup() { _max_interval = (Universe::get_heap_free_at_last_gc() / M) * SoftRefLRUPolicyMSPerMB; assert(_max_interval >= 0,"Sanity check"); }
可能导致的问题
使用第三方缓存 内部使用sorftRefrece封装.缓存占比太大 可能导致长时间得不到回收 而导致大量fullgc
或者是大量反射 反射后的元数据就是通过sorfRefrece封装 参考:https://www.sohu.com/a/124124072_494943
我们线上设置的-XX:SoftRefLRUPolicyMSPerMB=0 理论上每次GC都会回收。
参考:
https://www.cnblogs.com/mfrank/p/10154535.html
https://www.cnblogs.com/mfrank/p/10154535.html
https://article.pchome.net/content-2026644.html