看过SoftReference类的java源码,是不是会疑惑clock的值是怎么来的?
找找C++源码。。。。。。(jdk版本: jdk9-b66)
hotspot/src/share/vm/memory/referenceProcessor.cpp
void ReferenceProcessor::init_statics() { // We need a monotonically non-decreasing time in ms but // os::javaTimeMillis() does not guarantee monotonicity. jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; // Initialize the soft ref timestamp clock. _soft_ref_timestamp_clock = now; // Also update the soft ref clock in j.l.r.SoftReference java_lang_ref_SoftReference::set_clock(_soft_ref_timestamp_clock); _always_clear_soft_ref_policy = new AlwaysClearPolicy(); _default_soft_ref_policy = new COMPILER2_PRESENT(LRUMaxHeapPolicy()) NOT_COMPILER2(LRUCurrentHeapPolicy()); if (_always_clear_soft_ref_policy == NULL || _default_soft_ref_policy == NULL) { vm_exit_during_initialization("Could not allocate reference policy object"); } guarantee(RefDiscoveryPolicy == ReferenceBasedDiscovery || RefDiscoveryPolicy == ReferentBasedDiscovery, "Unrecognized RefDiscoveryPolicy"); }
此处将clock设置为当前时间。
此文件中有个函数process_discovered_references
ReferenceProcessorStats ReferenceProcessor::process_discovered_references( BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete_gc, AbstractRefProcTaskExecutor* task_executor, GCTimer* gc_timer, GCId gc_id) { NOT_PRODUCT(verify_ok_to_handle_reflists()); assert(!enqueuing_is_done(), "If here enqueuing should not be complete"); // Stop treating discovered references specially. disable_discovery(); // If discovery was concurrent, someone could have modified // the value of the static field in the j.l.r.SoftReference // class that holds the soft reference timestamp clock using // reflection or Unsafe between when discovery was enabled and // now. Unconditionally update the static field in ReferenceProcessor // here so that we use the new value during processing of the // discovered soft refs. _soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock(); bool trace_time = PrintGCDetails && PrintReferenceGC; // Soft references size_t soft_count = 0; { GCTraceTime tt("SoftReference", trace_time, false, gc_timer, gc_id); soft_count = process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true, is_alive, keep_alive, complete_gc, task_executor); } update_soft_ref_master_clock(); // Weak references size_t weak_count = 0; { GCTraceTime tt("WeakReference", trace_time, false, gc_timer, gc_id); weak_count = process_discovered_reflist(_discoveredWeakRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); } // Final references size_t final_count = 0; { GCTraceTime tt("FinalReference", trace_time, false, gc_timer, gc_id); final_count = process_discovered_reflist(_discoveredFinalRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); } // Phantom references size_t phantom_count = 0; { GCTraceTime tt("PhantomReference", trace_time, false, gc_timer, gc_id); phantom_count = process_discovered_reflist(_discoveredPhantomRefs, NULL, false, is_alive, keep_alive, complete_gc, task_executor); // Process cleaners, but include them in phantom statistics. We expect // Cleaner references to be temporary, and don't want to deal with // possible incompatibilities arising from making it more visible. phantom_count += process_discovered_reflist(_discoveredCleanerRefs, NULL, true, is_alive, keep_alive, complete_gc, task_executor); } // Weak global JNI references. It would make more sense (semantically) to // traverse these simultaneously with the regular weak references above, but // that is not how the JDK1.2 specification is. See #4126360. Native code can // thus use JNI weak references to circumvent the phantom references and // resurrect a "post-mortem" object. { GCTraceTime tt("JNI Weak Reference", trace_time, false, gc_timer, gc_id); if (task_executor != NULL) { task_executor->set_single_threaded_mode(); } process_phaseJNI(is_alive, keep_alive, complete_gc); } return ReferenceProcessorStats(soft_count, weak_count, final_count, phantom_count); }
然后一步一步的执行到了 policy->should_clear_reference
Java提供了几种SoftReference策略
这四种策略在文件jdk9/hotspot/src/share/vm/memory/referencePolicy.hpp中定义(代码这里就不贴了)
前两种没必要研究
3,4 在文件jdk9/hotspot/src/share/vm/memory/referencePolicy.cpp中
#include "precompiled.hpp" #include "classfile/javaClasses.hpp" #include "memory/referencePolicy.hpp" #include "memory/universe.hpp" #include "runtime/arguments.hpp" #include "runtime/globals.hpp" LRUCurrentHeapPolicy::LRUCurrentHeapPolicy() { setup(); } // Capture state (of-the-VM) information needed to evaluate the policy void LRUCurrentHeapPolicy::setup() { _max_interval = (Universe::get_heap_free_at_last_gc() / M) * SoftRefLRUPolicyMSPerMB; assert(_max_interval >= 0,"Sanity check"); } // The oop passed in is the SoftReference object, and not // the object the SoftReference points to. 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"); // The interval will be zero if the ref was accessed since the last scavenge/gc. if(interval <= _max_interval) { return false; } return true; } /////////////////////// MaxHeap ////////////////////// LRUMaxHeapPolicy::LRUMaxHeapPolicy() { setup(); } // Capture state (of-the-VM) information needed to evaluate the policy void LRUMaxHeapPolicy::setup() { size_t max_heap = MaxHeapSize; max_heap -= Universe::get_heap_used_at_last_gc(); max_heap /= M; _max_interval = max_heap * SoftRefLRUPolicyMSPerMB; assert(_max_interval >= 0,"Sanity check"); } // The oop passed in is the SoftReference object, and not // the object the SoftReference points to. bool LRUMaxHeapPolicy::should_clear_reference(oop p, jlong timestamp_clock) { jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p); assert(interval >= 0, "Sanity check"); // The interval will be zero if the ref was accessed since the last scavenge/gc. if(interval <= _max_interval) { return false; } return true; }
仔细看看发现
【下面写了一堆 还是删掉了,直接看代码吧,都能懂】
总结下:
存活时间大于_max_interval就回收
就是3,4策略对于_max_interval的计算方式不同
这里涉及到一个配置项 -XX:SoftRefLRUPolicyMSPerMB=1000
LRUCurrentHeapPolicy:当前堆可用空间,每兆1000毫秒
LRUMaxHeapPolicy: (当前堆大小-已使用的)
_heap_capacity_at_last_gc - _heap_used_at_last_gc
LRUMaxHeapPolicy: (最大堆大小-已使用的)
MaxHeapSize - _heap_used_at_last_gc
-----------------------------------------------如有错误请指正------------------------------