当您丢弃对 SoftReference 的引用时,它的清除是否仍会放在 ReferenceQueue 中?
When you discard the reference to a SoftReference, will it's clearing still be put on the ReferenceQueue?
我想了解垃圾收集器在什么情况下通知您清除软引用。文档清楚地说明了 OOM 可能发生时会发生这种情况,但是如果您完全丢弃引用,GC 会过来收集 SoftReference 可能会注意到不存在其他 strong/softly 引用并清除内部引用值。
ReferenceQueue<Object> cleared = new ReferenceQueue<>();
Object X = new Object();
SoftReference<Object> Xs = new SoftReference<>(X, cleared);
Thread.sleep(10);
X = null;
Xs = null;
System.GC();
Thread.sleep(100);
Reference ref;
while ((ref = cleared.poll()) != null) {
System.err.println(ref);
}
那么这个队列的规则记录在哪里?肯定有比我问的更多的极端情况,所以也许这个问题必须扩大一点。
看来你的问题不止一个。第一个是当引用将出现在引用队列中时。
文档(故意的?)留有解释空间,摘自 here:
Provides reference-object classes, which support a limited degree of interaction with the garbage collector. A program may use a reference object to maintain a reference to some other object in such a way that the latter object may still be reclaimed by the collector. A program may also arrange to be notified some time after the collector has determined that the reachability of a given object has changed.
因此,它发生在 之后的某个时间。在当前实现下它是一个异步进程,所以文档没有错。
你的第二个问题以错误的前提开始:
... GC will come around and collect the SoftReference...
不是真的。如果无法访问,GC 甚至 不知道 这个 SoftReference 的存在。 GC 发现 alive 个对象,其他一切都是垃圾,听起来很奇怪。因此 GC 甚至不知道有一个 SoftReference,因为它从不访问它。发生这种情况时,ReferenceQueue
上没有任何内容。为此,需要遍历 SoftReference
,但由于那从未发生过...
仅仅因为 SoftReference
无法访问并不意味着所指对象也一样。指示对象是强可达的,但 SoftReference
是不可到达的。
关于你的最后一点(我的意思是你会关心):当 SR 可访问,但指称对象已死时。 GC发现这种东西的时候,应该把referent清除掉(后面get
会return null
)和ReferenceQueue
上的post对不对?嗯,差不多。这取决于实际的GC。作为一个反例,以 Shenandoah GC
为例,它有一个名为 ShenandoahRefProcFrequency
的标志(默认为 5)。它显示了弱引用应该多久被清除一次,如果不是5
,当这种情况发生时:引用被声明"alive"。在达到该限制之前,该指称物会被人为地保持生命。
相关点可以在the package documentation的Notification部分找到:
The relationship between a registered reference object and its queue is one-sided. That is, a queue does not keep track of the references that are registered with it. If a registered reference becomes unreachable itself, then it will never be enqueued. It is the responsibility of the program using reference objects to ensure that the objects remain reachable for as long as the program is interested in their referents.
所以答案很简单。由于您将引用 SoftReference
的唯一变量设置为 null
,因此它永远不会被排队。它是否会被收集或清除,并不重要,因为你无法感知它。在实践中,典型的实现会像 Eugene 所写的那样,垃圾收集器只遍历实时引用,并不关心剩余内存中存在什么样的垃圾。
我想了解垃圾收集器在什么情况下通知您清除软引用。文档清楚地说明了 OOM 可能发生时会发生这种情况,但是如果您完全丢弃引用,GC 会过来收集 SoftReference 可能会注意到不存在其他 strong/softly 引用并清除内部引用值。
ReferenceQueue<Object> cleared = new ReferenceQueue<>();
Object X = new Object();
SoftReference<Object> Xs = new SoftReference<>(X, cleared);
Thread.sleep(10);
X = null;
Xs = null;
System.GC();
Thread.sleep(100);
Reference ref;
while ((ref = cleared.poll()) != null) {
System.err.println(ref);
}
那么这个队列的规则记录在哪里?肯定有比我问的更多的极端情况,所以也许这个问题必须扩大一点。
看来你的问题不止一个。第一个是当引用将出现在引用队列中时。
文档(故意的?)留有解释空间,摘自 here:
Provides reference-object classes, which support a limited degree of interaction with the garbage collector. A program may use a reference object to maintain a reference to some other object in such a way that the latter object may still be reclaimed by the collector. A program may also arrange to be notified some time after the collector has determined that the reachability of a given object has changed.
因此,它发生在 之后的某个时间。在当前实现下它是一个异步进程,所以文档没有错。
你的第二个问题以错误的前提开始:
... GC will come around and collect the SoftReference...
不是真的。如果无法访问,GC 甚至 不知道 这个 SoftReference 的存在。 GC 发现 alive 个对象,其他一切都是垃圾,听起来很奇怪。因此 GC 甚至不知道有一个 SoftReference,因为它从不访问它。发生这种情况时,ReferenceQueue
上没有任何内容。为此,需要遍历 SoftReference
,但由于那从未发生过...
仅仅因为 SoftReference
无法访问并不意味着所指对象也一样。指示对象是强可达的,但 SoftReference
是不可到达的。
关于你的最后一点(我的意思是你会关心):当 SR 可访问,但指称对象已死时。 GC发现这种东西的时候,应该把referent清除掉(后面get
会return null
)和ReferenceQueue
上的post对不对?嗯,差不多。这取决于实际的GC。作为一个反例,以 Shenandoah GC
为例,它有一个名为 ShenandoahRefProcFrequency
的标志(默认为 5)。它显示了弱引用应该多久被清除一次,如果不是5
,当这种情况发生时:引用被声明"alive"。在达到该限制之前,该指称物会被人为地保持生命。
相关点可以在the package documentation的Notification部分找到:
The relationship between a registered reference object and its queue is one-sided. That is, a queue does not keep track of the references that are registered with it. If a registered reference becomes unreachable itself, then it will never be enqueued. It is the responsibility of the program using reference objects to ensure that the objects remain reachable for as long as the program is interested in their referents.
所以答案很简单。由于您将引用 SoftReference
的唯一变量设置为 null
,因此它永远不会被排队。它是否会被收集或清除,并不重要,因为你无法感知它。在实践中,典型的实现会像 Eugene 所写的那样,垃圾收集器只遍历实时引用,并不关心剩余内存中存在什么样的垃圾。