我目前正在尝试诊断应用程序中的缓慢内存泄漏.我到目前为止的事实如下.
尽管只是被WeakReferences引用(根据Eclipse Memory Analyzer Tool),但是可能导致这些Foo类无法收集的原因是什么?
EDIT1:
@mindas我使用的WeakReference等同于以下示例代码.
public class FooWeakRef extends WeakReference<Foo>
{
public long longA;
public long longB;
public String stringA;
public FooWeakRef(Foo xiObject, ReferenceQueue<Foo> xiQueue)
{
super(xiObject, xiQueue);
}
}
Run Code Online (Sandbox Code Playgroud)
Foo没有终结器,只要没有清除WeakRefs,任何终结器都不会被考虑.当一个对象弱可达时,它不能最终确定.有关详情,请参阅此页面.
@kasten在对象可最终化之前清除弱引用.我的堆转储显示这没有发生.
@jarnbjo我引用WeakReference Javadoc:
"假设垃圾收集器在某个时间点确定一个对象是弱可达的.那时它将原子地清除对该对象的所有弱引用以及对该对象可从其访问的任何其他弱可达对象的所有弱引用通过一系列强大而柔软的参考资料."
这告诉我,GC应该检测到我的Foo对象是"弱可达"和"当时"清除弱引用这一事实.
编辑2
@j flemm - 我知道40mb听起来并不多,但我担心4天内40mb意味着100天内4000mb.我读过的所有文档都表明,弱可达的对象不应该闲置几天.因此,我对如何在没有引用显示在堆转储中时强烈引用对象的任何其他解释感兴趣.
当一些悬空Foo对象存在时,我将尝试分配一些大对象,并查看JVM是否收集它们.但是,此测试需要几天时间才能完成设置.
编辑3
@jarnbjo - 我知道我不能保证JDK何时会注意到一个对象是弱可达的.但是,我认为重载4天的应用程序会为GC提供足够的机会来注意我的对象是弱可达的.4天后,我强烈怀疑其余的弱引用对象已经以某种方式泄露.
编辑4
@j flemm - 多数民众赞成真有意思!只是为了澄清,你是说GC正在你的应用程序上发生并且没有清除Soft/Weak refs?您能否告诉我有关您正在使用的JVM + GC配置的更多详细信息?我的应用程序使用80%堆的内存条来触发GC.我假设任何旧的GC的GC都会清除Weak refs.一旦内存使用率高于更高的阈值,您是否建议GC仅收集弱引用?这个更高的限制是否可配置?
编辑5
@j flemm - 关于在SoftRefs之前清除WeakRefs的评论与Javadoc一致,其中声明:SoftRef:"假设垃圾收集器在某个时间点确定一个对象可以轻柔地到达.那时它可以选择清除原子地对该对象的所有软引用以及对任何其他可通过一系列强引用访问该对象的软可引用对象的所有软引用.同时或稍后它会将那些新清除的软引用排入队列在参考队列中注册."
WeakRef:"假设垃圾收集器在某个时间点确定一个对象是弱可达的.那时它将原子地清除对该对象的所有弱引用以及对该对象的任何其他弱可达对象的所有弱引用可以通过一系列强引用和软引用来访问.同时它将声明所有以前弱可达的对象都可以最终确定.同时或稍后它会将那些新清除的弱引用排入队列.在参考队列中注册."
为清楚起见,您是说当您的应用程序具有超过50%的可用内存时垃圾收集器运行,并且在这种情况下它不会清除WeakRefs?当你的应用程序有超过50%的可用内存时,为什么GC会运行?我认为你的应用程序可能只是产生非常少量的垃圾,当收集器运行时它正在清除WeakRefs而不是SoftRef.
编辑6 …
我正在阅读"Scala编程"一书,并Rational
在第6章的实现中遇到了一些问题.
这是我Rational
班级的初始版本(基于本书)
class Rational(numerator: Int, denominator: Int) {
require(denominator != 0)
private val g = gcd(numerator.abs, denominator.abs)
val numer = numerator / g
val denom = denominator / g
override def toString = numer + "/" + denom
private def gcd(a: Int, b: Int): Int =
if(b == 0) a else gcd(b, a % b)
// other methods go here, neither access g
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是,字段g在类的生命周期内保持不变,即使从未再次访问过.运行以下模拟程序可以看到此问题:
object Test extends Application {
val a = new Rational(1, 2) …
Run Code Online (Sandbox Code Playgroud) 我正在使用VisualVM分析我的应用程序,我发现堆大小在大约3天内增加了大约7MB.当我使用内存采样器时,我也看到它java.lang.ref.WeakReference
在实例编号的前五位.数量WeakReference
正在增加,GC几乎没有影响.
任何的想法?