我有一个缓存,它具有对缓存对象的软引用。我正在尝试为类的行为编写功能测试,这些类使用缓存专门用于清除缓存对象时发生的事情。
问题是:我似乎无法可靠地获取要清除的软引用。简单地使用一堆内存并不能解决问题:在清除任何软引用之前,我会得到一个OutOfMemory。
有没有办法让Java更加热切地清理软引用?
找到here :
“虽然这一切都得到保证 SoftReferences之前会被清除 抛出OutOfMemoryError,所以他们 理论上不能引起OOME。“
这是否意味着上面的场景必须意味着我的内存泄漏,某些类在我的缓存对象上持有一个硬引用?
答案 0 :(得分:14)
问题是:我似乎无法做到 可靠地得到软引用 清零。
这不是SoftReferences独有的。由于Java中垃圾收集的性质,无法保证任何可垃圾收集的内容实际上都会在任何时间点收集。即使只是简单的代码:
Object temp = new Object();
temp = null;
System.gc();
无法保证在第一行中实例化的Object在此处或实际上任何点都是垃圾收集。它只是你用内存管理语言生活的东西之一,你放弃了对这些东西的陈述力。是的,这有时很难确定地测试内存泄漏。
也就是说,根据你引用的Javadocs,在抛出OutOfMemoryError之前,必须清除SoftReferences(实际上,这是它们的全部要点,也是它们与默认对象引用的唯一不同之处)。因此,听起来存在某种类型的内存泄漏,因为您需要对相关对象进行更难的引用。
如果对JVM使用-XX:+HeapDumpOnOutOfMemoryError
选项,然后将堆转储加载到jhat之类的内容中,您应该能够看到对象的所有引用,从而查看是否存在软的旁边的任何参考。或者,您可以在测试运行时使用分析器实现相同的功能。
答案 1 :(得分:14)
还有以下JVM参数用于调整软引用的处理方式:
-XX:SoftRefLRUPolicyMSPerMB=<value>
其中'value'是每个空闲Mb内存保留软引用的毫秒数。默认值为1s / Mb,因此如果一个对象只是软可达,如果只有1Mb的堆空间是空闲的,它将持续1秒。
答案 2 :(得分:5)
您可以使用此piece of code强制在测试中清除所有SoftReferences。
答案 3 :(得分:2)
如果您真的想要,可以在SoftReference上调用clear()来清除它。
也就是说,如果JVM抛出一个OutOfMemoryError并且你的SoftReference还没有被清除,那么这意味着你必须在其他地方有一个对该对象的硬引用。否则会使SoftReference的合同无效。否则,您永远无法保证SoftReference被清除:只要仍有可用内存,JVM就不需要清除任何SoftReferences。另一方面,它允许在下次进行GC循环时清除它们,即使它不需要。
此外,您可以考虑查看WeakReferences,因为虚拟机往往更具攻击性。从技术上讲,VM不需要清除WeakReference,但是如果该对象被认为是死的,它应该在下次GC循环时清理它们。如果您正在尝试测试清除缓存时会发生什么,使用WeakReferences可以帮助您的条目更快地消失。
另外,请记住,这两者都依赖于执行GC循环的JVM。不幸的是,没有办法保证其中一个发生过。即使你调用System.gc(),垃圾收集器也可能会认为它只是在做桃子并且选择什么都不做。
答案 4 :(得分:2)
在典型的JVM实现(SUN)中,您需要多次触发Full GC才能清除Softreferences。原因是因为Softreferences需要GC做更多工作,因为例如一种机制允许您在回收对象时得到通知。
恕我直言,在应用服务器中使用大量的软件参考是邪恶的,因为开发人员对它们何时被释放没有多少控制权。
答案 5 :(得分:1)
垃圾收集和其他引用(如软引用)是不确定的,因为它不可能可靠地执行操作,因此在那时肯定会清除软引用,因此您的测试可以判断您的缓存是如何反应的。我建议你通过模拟等以更明确的方式模拟参考清除 - 你的测试将是可重复的并且更有价值,而不仅仅是用于GC清理引用的Hopi g。使用后一种方法是一件非常糟糕的事情,并且只会引入其他问题,而不是帮助您提高缓存质量和协作组件。
答案 6 :(得分:0)
从文档和我的经验中我会说是:你必须在其他地方有参考。
我建议使用一个调试器,它可以显示对象的所有引用(例如调试Java 6时的Eclipse 3.4),并检查何时抛出OOM。
答案 7 :(得分:0)
如果使用eclipse,则有一个名为Memory Analyzer的工具可以更轻松地进行堆转储调试。
答案 8 :(得分:0)
缓存的对象是否有终结器?终结器将创建对该对象的新的强引用,因此即使清除了SoftReference,在稍后的GC循环之前也不会回收内存
答案 9 :(得分:-2)
如果你有一个缓存,这是一个SoftReferences地图,你希望它们被清除,你可以清除()地图,它们都将被清理(包括他们的参考)