我想知道这一点,因为这会使它们变得不那么有用。如果是这样,有没有办法让内存在主要 GC 上仅被弱引用为“垃圾”?
6 回答
javadoc 没有具体说明清除/破坏WeakReference
s 的“时间尺度”是什么。这将使您的问题的答案(至少在理论上)“它取决于实现”。事实上,JLS 规范和 javadocs 甚至都没有提到主要与次要集合。整个主题都在“实施细节”类别中。
如果您确实想要对 GC 敏感的引用,那么也许您应该使用 aSoftReference
代替。描述如下:
“保证在虚拟机抛出 OutOfMemoryError 之前已清除对软可访问对象的所有软引用。否则,不会对清除软引用的时间或一组此类引用的顺序施加任何限制不同的对象将被清除。但是,鼓励虚拟机实现偏向于清除最近创建或最近使用的软引用。
在其他地方,软引用被描述为比弱引用更强。这意味着它不太可能被破坏;例如,过度渴望的垃圾收集器。但请注意,这些都没有谈论主要与次要垃圾收集。
更新我在 Java 11 源代码树的https://stackoverflow.com/a/16977182/139985中研究了以下(非常合理的!)声明:
次要收集将收集年轻空间中的任何对象。年轻空间中的
WeakReference
对象将在次要 GC 上收集。
本机引用处理代码很复杂。有一个通用ReferenceProcessor
类执行以下操作:
- 它选择性地记录
Reference
GC 遇到的对象。GC 代码调用ReferenceProcessor::discover_reference
来实现这一点。 - 它迭代发现的
Reference
对象以确定是否破坏引用。相关Reference
对象被添加到它们各自的引用队列中。
并发症如下:
GC 可能会或可能不会调用
ReferenceProcessor::discover_reference
. 据我所知,大多数(如果不是全部)GC 都会调用它,但很难确定。对于
ReferenceProcessor
处理引用和所指对象在不同代(或跨度)中的情况,有不同的策略。(如果不处理引用,则该引用将被视为当前集合难以访问。)
简而言之,我可以确认Reference
对象通常会在次要 GC 中处理。但是,特定的实际行为Reference
可能取决于生成/跨度问题。
(应该可以从 GC 日志中观察特定 GC 的一般行为。查找参考处理阶段的统计信息或时间。)
1 - 评论中使用了“span”一词。我认为它与将老年代分成多个单独收集的区域(跨度)的收集器(例如 G1)有关。
你为什么要那个?您的程序不应该太在意主要和次要 GC 周期,事实上,这种差异甚至不会存在于所有 JVM / GC 配置中。
WeakReference
只要没有对该对象的强引用,s 就可以收集。这可能包括次要 GC。
如果您希望对象停留一段时间直到出现实际内存压力,请尝试使用SoftReference。
您可能正在考虑可能更接近您想要的 SoftReferences。
次要收集将收集年轻空间中的任何对象。对年轻空间中对象的弱引用将在次要 GC 上收集。对长期空间中的对象的弱引用将在长期收集中收集,例如 Full GC。顺便说一句,您只能同时收集终身空间。
这取决于 WeakReference 对象是否在 Eden 中 - 次要集合只会查看 Eden 中的对象。
WeakReference
不会阻止对象的收集,因此如果对象属于年轻空间并且只能通过弱引用访问,它将被收集。
SoftReferences
(在 HotSpot JVM 中)作为弱引用或强引用,取决于上次访问时间戳(上次调用get()
引用的时间戳)。sotf 引用的“到期时间”计算为可用内存大小乘以通过配置的系数-XX:SoftRefLRUPolicyMSPerMB=T
(例如,更少的可用内存,软引用的短到期时间)。
通常,使用 JVM 引用进行缓存是一个坏主意: - 它将临时对象提升到旧空间,打破了弱代假设 - 引用以特殊方式受到 GC 增加次要 GC 时间的威胁
如果您需要带有驱逐策略的缓存,最好明确实现它并考虑影响驱逐策略中存储数据的内存占用。