看起来它可能是可调的,但事实并非如此。并发标记清除收集器挂在默认堆的实现上,
must_clear_all_soft_refs()该堆显然仅
true在执行时才执行
_last_ditch_collection。
bool GenCollectedHeap::must_clear_all_soft_refs() { return _gc_cause == GCCause::_last_ditch_collection;}虽然正常处理失败的分配具有对堆
do_collect方法的三个连续调用,但在
CollectorPolicy.cpp
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) {尝试收集,尝试重新分配,如果失败,则尝试扩展堆,然后作为最后的努力,尝试收集清除软引用。
对最后一个集合的评论很有说服力(也是唯一一个触发清除软引用的评论)
// If we reach this point, we're really out of memory. Try every trick // we can to reclaim memory. Force collection of soft references. Force // a complete compaction of the heap. Any additional methods for finding // free memory should be here, especially if they are expensive. If this // attempt fails, an OOM exception will be thrown. { IntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted gch->do_collection(true , true , size , is_tlab , number_of_generations() - 1 ); }-–为回应显而易见的内容而编辑,我描述的是弱引用,而不是软引用-
在实践中,我可以想象当调用JVM进行垃圾回收以响应它们试图避免时,SoftReferences只会被“不”跟随
OutOfMemoryError。
为了使
SoftReferences与所有四个Java
1.4垃圾收集器以及新的G1收集器兼容,决策必须仅取决于可到达性确定。到收割和压实发生时,确定某个对象是否可触及为时已晚。这表明(但不要求)存在一个集合“上下文”,该集合根据堆中的可用内存可用性确定可达性。这样的上下文必须
SoftReference在尝试关注之前指示不关注。
由于
OutOfMemoryError回避垃圾收集是按全收集的“停止世界”的方式专门安排的,因此很难想象堆管理器
SoftReference在收集发生之前设置“不遵循”标志的情况。
-–好的,所以我认为“必须以这种方式工作”的答案还不够好-
从源代码src / share / vm / gc_implementation / concurrentMarkSweep /
vmCMSOperations.cpp(突出显示是我的)
实际“执行”垃圾收集的操作:
170 void VM_GenCollectFullConcurrent::doit() {我们最好成为VM线程,否则“程序”线程就是垃圾回收!
171 assert(Thread::current()->is_VM_thread(), "Should be VM thread");
我们是并发收集器,因此最好同时进行调度!
172 assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected"); 173
抓取堆(其中具有GCCause对象)。
174 GenCollectedHeap* gch = GenCollectedHeap::heap();
检查是否需要前台“年轻”集合
175 if (_gc_count_before == gch->total_collections()) { 176 // The "full" of do_full_collection call below "forces" 177 // a collection; the second arg, 0, below ensures that 178 // only the young gen is collected. XXX In the future, 179 // we'll probably need to have something in this interface 180 // to say do this only if we are sure we will not bail 181 // out to a full collection in this attempt, but that's 182 // for the future.程序线程是否不干预堆?
183 assert(SafepointSynchronize::is_at_safepoint(), 184 "We can only be executing this arm of if at a safepoint");
从堆中获取垃圾回收原因(此回收的原因)。
185 GCCauseSetter gccs(gch, _gc_cause);
充分收集年轻空间
请注意,他传递了堆的must_clear_all_soft_refs标志的值,该标志在OutOfMemory场景中必须已设置为true,并且无论哪种情况,都将“
do_full_collection”定向为不遵循软引用
186 gch->do_full_collection(gch->must_clear_all_soft_refs(), 187 0 );
_gc_cause是一个枚举,
_allocation_failure在第一次尝试中将其设置为(guesswork)以避免
OutOfMemoryError,
_last_ditch_collection然后失败(尝试收集临时垃圾)
快速浏览一下内存“堆”模块,发现
do_full_collection其中的
do_collection软引用的调用已使用行显式清除(在“正确”条件下)
480 ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
-–那些想要学习弱引用的人的原始帖子如下-
在标记和清除算法中,主线程 不会 遵循软引用(因此不会进行标记,除非其他分支可以通过非软引用到达软引用)。
在复制算法中,对象软引用指向的对象 不会被 复制(同样,除非其他非软引用到达了它们)。
基本上,从“主”执行线程中遵循引用Web时, 不 遵循软引用。这允许对它们的对象进行垃圾回收,就像它们没有指向它们的引用一样。
重要的是要提到,软引用几乎 永远不会
孤立地使用。它们通常用于设计要对该对象有多个引用的对象中,但是只需要清除一个引用即可触发垃圾回收(为便于维护容器或无需查找昂贵的引用的运行时性能) 。



