TLDR:我如何才能强制JVM不对我的对象进行垃圾收集,即使我不想以任何有意义的方式使用它们?
更长的故事:我有一些 Item 是从永久存储中加载的,并作为弱引用保存在缓存中。弱引用的使用意味着,除非有人实际上正在使用特定的 Item,否则没有对它们的强引用,未使用的引用最终会被垃圾收集。这是所有期望的行为,工作得很好。此外,有时需要将 Item 的更改传播到永久存储中。2这是在一个专用的写线程中异步完成的。3问题来了,因为我显然不能允许在更新完成之前对 * Item * 进行垃圾收集。(Item 在更新过程中实际上从未使用,只是保留)。
public class Item {
public final String name;
public String value;
}
public class PendingUpdate {
public final Item strongRef; // not actually necessary, just to avoid GC
public final String name;
public final String newValue;
}
但是经过一番思考和挖掘之后,我在JavaSE规范(12.6.1)中找到了这一段:
可以设计程序的优化变换,以将可到达的对象的数量减少到少于那些被认为是可到达的对象的数量。例如,Java编译器或代码生成器可以选择将不再使用的变量或参数设置为空,以使用于这样的对象的存储可能更快地被回收。
如果我没理解错的话,这意味着java可以决定 Item 是垃圾。一个解决方案是在 Item 上做一些不必要的操作,比如在存储更新代码的末尾做item.hashCode();
。但是我认为JVM可能足够聪明,可以删除这些不必要的代码,我想不出任何合理的解决方案,一个足够聪明的JVM不会。I don“我不能在需要的时候提前释放。
public void performStorageUpdate(PendingUpdate update) {
final Transaction transaction = this.getDataManager().beginTransaction();
try {
// ... some permanent storage update code
} catch (final Throwable t) {
transaction.abort();
}
transaction.commit();
// The Item should never be garbage collected before this point
update.item.hashCode(); // Trying to avoid GC of the item, is probably not enough
}
有人遇到过弱引用的类似问题吗?是否有一些语言保证可以避免对此类对象使用GC?(理想情况下,性能影响尽可能小。)或者是我想多了,规范段落的意思有所不同?
编辑:为什么我不能允许 Item 在存储更新完成之前进行垃圾回收:有问题的事件顺序:
1.项目已载入快取并使用(做为强式指涉保留)
1.对项目的更新已入队
1.删除了对Item的强引用,并且没有其他对Item的强引用(除了PendingUpdate中的强引用,但正如我所解释的,我认为JVM可以优化掉那个强引用)。
1.项目已被垃圾回收
1.再次请求项,并从永久存储中加载该项,同时创建对该项的新强引用
1.执行存储更新结果状态:该高速缓存和永久存储中有不一致的数据。因此,我需要保留对Item的强引用,直到存储更新完成,但我只需要保留它,实际上不需要对它做任何事情(所以JVM可能会认为可以安全地删除它)。
1条答案
按热度按时间jq6vz3qz1#
TL;DR如何强制JVM不对我的对象进行垃圾回收,即使我不想以任何有意义的方式使用它们?
使它们强可达;例如,将它们添加到一个强可达的数据结构中。如果对象是强可达的,那么垃圾收集器就不会中断对它们的弱引用。
当您完成需要将对象保留该高速缓存中的行程时,您可以清除数据结构,以中断上述的强式指涉。下次执行GC时,就可以中断弱式指涉。
如果我没理解错的话,这意味着java可以直接决定Item是垃圾。
不是这个意思。
它的真正含义是基础结构可以确定一个对象是“有效地”不可访问的,即使在变量中仍然存在对它的引用。例如:
如果编译器/运行时可以确定
big
所引用的对象在长时间计算期间不能使用1,则允许在长时间计算期间对其进行垃圾回收。但问题是,只有当对象 * 不能 * 被使用时,它才能这样做。如果它不能被使用,就没有理由不对它进行垃圾收集。
1 -...不遍历引用对象。
值得注意的是,强可达的定义并不 * 只是 * 在一个局部变量中有一个引用。
它没有 * 指定 * 线程如何到达对象,或者运行时如何推断没有线程可以到达它。
但这意味着如果线程只能通过引用对象访问对象,那么它就不是强可达的。
因此......使对象强可达。