另一个强制Java垃圾收集问题(我认为这是一个合理的用例)
我有一个数据生成器,它生成的数据由许多不同的消费者使用(我们称之为Cs)。每个C都有自己感兴趣的数据集。数据生产者对Cs的引用较弱,因此可以通知他们进行更新 每个C也被许多独立的组件使用,因此没有一个组件可以告诉我们何时不再需要C,所以我们必须让JVM来确定C何时可以GC 这里的目标是在C过时时得到通知,以便数据生产者可以关闭只对未使用的C感兴趣的数据 正如我前面提到的,数据生产者总是对Cs有弱引用,所以当C是GCed时,很容易做到这一点。然而,我注意到,Cs通常在最终GC ed之前在VM中停留很长一段时间,而在这段时间里,数据生产者产生了大量它应该需要的数据 我有没有办法强制对未使用的Cs进行GC?我希望答案是肯定的,但我希望答案是否定的,所以作为后续问题,是否有人对我如何(重新)设计它以使其更好/更有效有好的建议 谢谢 下面的一些答案提出了很多好的观点,特别是关于强制C用户订阅和取消订阅的建议。这很困难,因为:另一个强制Java垃圾收集问题(我认为这是一个合理的用例),java,garbage-collection,Java,Garbage Collection,我有一个数据生成器,它生成的数据由许多不同的消费者使用(我们称之为Cs)。每个C都有自己感兴趣的数据集。数据生产者对Cs的引用较弱,因此可以通知他们进行更新 每个C也被许多独立的组件使用,因此没有一个组件可以告诉我们何时不再需要C,所以我们必须让JVM来确定C何时可以GC 这里的目标是在C过时时得到通知,以便数据生产者可以关闭只对未使用的C感兴趣的数据 正如我前面提到的,数据生产者总是对Cs有弱引用,所以当C是GCed时,很容易做到这一点。然而,我注意到,Cs通常在最终GC ed之前在VM中停留
C只是接口I的一种可能实现(接口I没有订阅要求),这是用户真正使用的接口。C实现是在运行时注入的,因此我们不能强制用户遵守C特定的要求。(哎哟?使用C的组件可以在感兴趣和不再感兴趣时发出通知 当至少有一个感兴趣的组件时,启用订阅。(在此之前不会出现这种情况),当最后一个组件取消订阅时,关闭数据
Set<C> components = ...
public void subscribesTo(C component) {
if (components.isEmpty())
enableSubscription();
components.add(component);
}
public void unsubscribeFrom(C component) {
components.remove(component);
if (components.isEmpty())
disableSubscription();
}
设置组件=。。。
公共无效订阅(C组件){
if(components.isEmpty())
启用订阅();
组件。添加(组件);
}
公共无效取消订阅(C部分){
组件。移除(组件);
if(components.isEmpty())
禁用订阅();
}
也许我们可以先澄清一下您的体系结构。你有:
通过调用
System.gc()
您建议VM对内存状况采取措施。我引用javadoc的话:
当控件从方法调用返回时,Java虚拟机已尽最大努力从所有丢弃的对象中回收空间
注意,这并不意味着它实际上已经执行了GC,它只是检查是否需要执行。实际上,我还没有看到VM忽略System.gc()
调用
通常你不必也不应该这样做。VM比您(和我)对内存子系统的行为有更好的理解。但是,在某些情况下,如果应用程序行为不常见,并且您知道需要内存,那么就可以这样做。您不能强制JVM进行垃圾收集,最好通过调用
System.gc()
来提出建议
也许更好的解决方案是引入某种侦听器模式,让您的Cs向数据生成器注册/注销,独立组件向您的C注册。当从您的C注销时,它可以检查是否不再需要它,在这种情况下,它可以从数据生成器中注销。我只使用System.gc() 在这篇相关文章中有一些非常有趣的信息:
显然,许多IDE也使用它来评估可用堆的数量。我想没有理由我也不能这么做。谢谢。问题是,Cs是一个现有的类,它被无数不同的目的使用,现在要求所有用户在使用它之前订阅它是不切实际的。此外,我们也无法强制C用户在使用C后会体面地取消订阅,这可能会导致严重的内存和资源泄漏。@RAY:如果您不能确保C用户正确关闭它,您如何确保他们会放弃对C的任何引用?如果您有不可靠、无法维护的代码,效率不应该是一个考虑因素,你只需要按照有效的方法去做,并希望做到最好。@Joachim Sauer这是公平的观点。我想区别在于,如果用户要明确地做到这一点,我们会要求他们更加勤奋。机会是(就像我的例子一样),这些用户不会长寿,当他们自己死后,C的引用就被释放了。C的实现试图适应更通用的范例。假设它实现了一些接口I,只是众多实现中的一个。C的用户实际上是I的用户,因此要求他们了解C特定的需求是可行的(或正确的?),谢谢。我想这和彼得·劳里的建议是一样的。Cs是由不需要对C类有深入了解的人/程序使用的,因此很难强迫他们注册