JVM如何在实践中收集SoftReferences? [英] How are SoftReferences collected by JVMs in practice?

查看:137
本文介绍了JVM如何在实践中收集SoftReferences?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在JVM中运行的两个单独的缓存(一个由第三方库控制),每个缓存都使用软引用。我希望JVM在由库控制的缓存之前清除我的受控缓存。 SoftReference javadoc声明:

I have two separate caches running in a JVM (one controlled by a third party library) each using soft references. I would prefer for the JVM to clear out my controlled cache before the one controlled by the library. The SoftReference javadoc states:


对虚拟可访问对象的所有软引用都保证在虚拟机引发之前清除
OutOfMemoryError。
否则,不会对清除软
引用的时间或清除一组此类
引用不同对象的顺序进行约束。但是,鼓励虚拟机
实现偏向清除最近创建的或最近使用的软引用

All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError. Otherwise no constraints are placed upon the time at which a soft reference will be cleared or the order in which a set of such references to different objects will be cleared. Virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references.

此类的直接实例可用于实现简单的缓存;
此类或派生子类也可用于较大的数据
结构,以实现更复杂的缓存。只要软引用的
指示对象是强可达的,即实际使用的是
,软引用将不会被清除。因此,例如,一个
复杂的缓存可以通过保持对这些
条目的强烈引用来防止其最近使用的
条目被丢弃,而剩余的条目将被丢弃在
垃圾收集器的自由裁量权。

Direct instances of this class may be used to implement simple caches; this class or derived subclasses may also be used in larger data structures to implement more sophisticated caches. As long as the referent of a soft reference is strongly reachable, that is, is actually in use, the soft reference will not be cleared. Thus a sophisticated cache can, for example, prevent its most recently used entries from being discarded by keeping strong referents to those entries, leaving the remaining entries to be discarded at the discretion of the garbage collector.

常见的JVM实现,特别是HotSpot,如何在实践中处理SoftReferences?他们是否反对清除最近创建的或最近使用的软参考,这是由规范鼓励的?

How do common JVM implementations, especially HotSpot, handle SoftReferences in practice? Do they "bias against clearing recently-created or recently-used soft references" as encouraged to by the spec?

推荐答案

看起来像它可以是可调的,但事实并非如此。并发标记扫描收集器挂起默认堆的 must_clear_all_soft_refs()的实现,当执行a时,它显然只是 true _last_ditch_collection

Looks like it could be tuneable, but it isn't. The concurrent mark-sweep collector hangs on the default heap's implementation of must_clear_all_soft_refs() which apparently is only true when performing a _last_ditch_collection.

bool GenCollectedHeap::must_clear_all_soft_refs() {
  return _gc_cause == GCCause::_last_ditch_collection;
}

虽然正常处理失败的分配有三次连续调用堆的 do_collect 方法,在 CollectorPolicy.cpp

While normal handling of failed allocation has three successive calls to the heap's do_collect method, in the CollectorPolicy.cpp

HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size,
                                                    bool   is_tlab) {

尝试收集,尝试重新分配,尝试扩展堆,如果失败,然后作为最后努力,尝试收集清算软引用。

Which tries to collect, tries to reallocate, tries to expand the heap if that fails, and then as a last-ditch effort, tries to collect clearing soft references.

关于最后一个集合的评论非常明确(并且是唯一一个触发清算软件的人)

The comment on the last collection is quite telling (and the only one that triggers clearing soft refs)

  // 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 */);
  }

---编辑以回应显而易见的,我在描述弱引用,不软的---

--- Edited in response to the obvious, I was describing weak references, not soft ones ---

在实践中,我认为当JVM被调用以进行垃圾收集以响应他们试图避免时,只会不遵循SoftReferences OutOfMemoryError

In practice, I would imagine that SoftReferences are only "not" followed when the JVM is called for garbage collection in response to they attempt to avoid an OutOfMemoryError.

对于 SoftReference ,要与所有四个Java 1.4垃圾收集器兼容,并与新的G1收集器兼容,决定必须只有可达性确定。当收割和压缩发生时,判断对象是否可达是为时已晚。这表明(但不要求)存在集合上下文,该集合基于堆中的可用内存可用性来确定可达性。在尝试跟踪它们之前,这样的上下文必须指示不遵循 SoftReference

For SoftReferences to be compatible with all four Java 1.4 garbage collectors, and with the new G1 collector, the decision must lie only with the reachability determination. By the time that reaping and compacting occur, it is far too late to decide if an object is reachable. This suggests (but does not require) that a collection "context" exists which determines reachability based on free memory availability in the heap. Such a context would have to indicate not following SoftReferences prior to attempting to follow them.

OutOfMemoryError 避免垃圾收集是以完整集合,世界各地的方式特别安排的,这不是一个难以想象的情况,堆管理器设置不遵循 SoftReference 收集前的标志。

Since OutOfMemoryError avoidance garbage collection is specially scheduled in a full-collection, stop-the-world manner, it would not be a hard to imagine scenario where the heap manager sets a "don't follow SoftReference" flag before the collection occurs.

---好的,所以我决定必须工作这个方式回答不够好​​---

--- Ok, so I decided that a "must work this way" answer just wasn't good enough ---

源代码 src / share / vm / gc_implementation / concurrentMarkSweep / vmCMSOperations.cpp (重点是我的)

From the source code src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp (highlights are mine)

实际做垃圾收集的操作:

The operation to actually "do" garbage collection:

  170 void VM_GenCollectFullConcurrent::doit() {

我们最好是VM线程,否则程序线程是垃圾收集!

We better be a VM thread, otherwise a "program" thread is garbage collecting!

  171   assert(Thread::current()->is_VM_thread(), "Should be VM thread");

我们是并发收藏家,所以我们最好同时安排!

We are a concurrent collector, so we better be scheduled concurrently!

  172   assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected");
  173 

抓住堆(其中包含GCCause对象)。

Grab the heap (which has the GCCause object in it).

  174   GenCollectedHeap* gch = GenCollectedHeap::heap();

检查我们是否需要前景年轻系列

Check to see if we need a foreground "young" collection

  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.

程序线程是否不干涉堆?

Are the program threads not meddling with the heap?

  183     assert(SafepointSynchronize::is_at_safepoint(),
  184       "We can only be executing this arm of if at a safepoint");

从堆中获取垃圾收集原因(此收集的原因)。

Fetch the garbage collection cause (the reason for this collection) from the heap.

  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 之后失败(尝试收集)瞬态垃圾)

The _gc_cause is an enum, which is (guesswork here) set to _allocation_failure in the first attempt at avoiding OutOfMemoryError and _last_ditch_collection after that fails (to attempt to collect transient garbage)

快速查看内存堆模块显示在 do_full_collection 中调用 do_collection 使用行显式清除(在正确条件下)软引用

A quick look in the memory "heap" module shows that in do_full_collection which calls do_collection soft references are cleared explicitly (under the "right" conditions) with the line

  480   ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());

---对于想要了解弱引用的人来说,原帖如下---

--- Original post follows for those who want to learn about weak references ---

在Mark and Sweep算法中,Soft引用是而不是从主线程跟随(因此没有标记,除非另一个分支可以通过非软引用。

In the Mark and Sweep algorithm, Soft references are not followed from the Main thread (and thus not marked unless a different branch could reach it through non-soft references.

在复制算法中,对象软引用指向的是复制(除非它们通过不同的非软到达)参考)。

In the copy algorithm, Objects soft references point to are not copied (again unless they are reached by a different non-soft reference).

基本上,当遵循主执行线程的引用Web时,软引用后面。这允许他们的对象被垃圾收集,好像他们没有指向它们的引用。

Basically, when following the web of references from the "main" thread of execution, soft references are not followed. This allows their objects to be garbage collected just as if they didn't have references pointing to them.

重要的是要提到软引用几乎永远不会隔离使用。它们通常用于设计要对对象进行多次引用的对象,但只需要清除一个引用来触发垃圾收集(为了便于维护容器,或者运行时不需要查找昂贵的引用)。

It is important to mention that soft references are almost never used in isolation. They are typically used in objects where the design is to have multiple references to the object, but only one reference need be cleared to trigger garbage collection (for ease of maintaining the container, or run time performance of not needing to look up expensive references).

这篇关于JVM如何在实践中收集SoftReferences?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆