看起来它可以调整,但事实并非如此。并发标记清除收集器挂在默认堆的实现上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 /* full */,
true /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
---针对显而易见的情况进行编辑,我描述的是弱引用,而不是软引用 ---
在实践中,我认为只有在调用 JVM 进行垃圾收集以响应他们试图避免OutOfMemoryError
.
要使SoftReference
s 与所有四个 Java 1.4 垃圾收集器以及新的 G1 收集器兼容,决定必须仅取决于可达性确定。等到 reaping 和 compaction 发生时,再决定一个对象是否可达已经太晚了。这表明(但不要求)存在一个集合“上下文”,它根据堆中的可用内存可用性确定可达性。这样的上下文必须SoftReference
在尝试遵循它们之前表明不遵循 s。
由于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 /* collect only youngest gen */);
_gc_cause 是一个枚举,它(这里是猜测)_allocation_failure
在第一次尝试避免时设置为OutOfMemoryError
,_last_ditch_collection
之后失败(尝试收集瞬态垃圾)
快速查看内存“堆”模块显示do_full_collection
调用do_collection
软引用被明确清除(在“正确”条件下)与行
480 ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
--- 原帖是为那些想了解弱引用的人准备的 ---
在 Mark and Sweep 算法中,主线程不遵循软引用(因此除非不同的分支可以通过非软引用到达它,否则不会被标记。
在复制算法中,软引用指向的对象不会被复制(同样,除非它们被不同的非软引用到达)。
基本上,当从“主”执行线程跟踪引用网络时,不遵循软引用。这允许它们的对象被垃圾收集,就像它们没有指向它们的引用一样。
值得一提的是,软引用几乎从不孤立地使用。它们通常用于对象中的设计是对对象有多个引用,但只需要清除一个引用即可触发垃圾收集(为了便于维护容器,或者不需要查找昂贵引用的运行时性能) .