Java内存泄漏:为什么不收集无法访问的对象?

Java内存泄漏:为什么不收集无法访问的对象?,java,memory-leaks,out-of-memory,nashorn,eclipse-memory-analyzer,Java,Memory Leaks,Out Of Memory,Nashorn,Eclipse Memory Analyzer,我正试图找到JDK Nashorn bug的解决方法 我用错误通知单中链接的脚本复制了错误,并进行了几次堆转储。我使用了JProfiler和Eclipse内存分析器 找到问题的根源。但是,我总是以无法到达的路径结束,我不明白为什么这些对象没有被垃圾收集。AFAI没有终结器来维持它们的生存。 如果我在JProfiler中打开堆转储而不禁用“完全GC-on-dump”,JProfiler甚至会丢弃无法访问的对象。但GC本身不会。我使用G1 GC进行了测试,但与CMS相同 使用任何JDK>8,您都可以

我正试图找到JDK Nashorn bug的解决方法

我用错误通知单中链接的脚本复制了错误,并进行了几次堆转储。我使用了JProfiler和Eclipse内存分析器 找到问题的根源。但是,我总是以无法到达的路径结束,我不明白为什么这些对象没有被垃圾收集。AFAI没有终结器来维持它们的生存。 如果我在JProfiler中打开堆转储而不禁用“完全GC-on-dump”,JProfiler甚至会丢弃无法访问的对象。但GC本身不会。我使用G1 GC进行了测试,但与CMS相同

使用任何JDK>8,您都可以在1-2分钟内通过以下设置运行脚本获得一个示例转储:
-Xmx20M-XX:+HeapDumpOnOutOfMemoryError

public class TestJsMemLeak
{
    public static final class JsJavaUtil
    {
        private long counter = 0;

        public long testFunc()
        {
            return counter++;
        }
    }

    public static void main(final String[] args) throws Exception
    {
        System.setProperty("nashorn.args", "--no-java -doe -ot=false --language=es6 --no-deprecation-warning --lazy-compilation=false");       
        for (long i = 0; true; ++i)
        {
            final ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("nashorn");
            scriptEngine.put("JsJavaUtil", new JsJavaUtil());
            scriptEngine.eval("for (var i = 0; i < 10; ++i) {\n" + " JsJavaUtil.testFunc();\n" + "}");
            System.gc();
            if (i % 100 == 0)
            {
                System.out.println(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
            }
        }
    }
}
公共类TestJsMemLeak
{
公共静态最终类JsJavaUtil
{
专用长计数器=0;
公共长testFunc()
{
返回计数器++;
}
}
公共静态void main(最终字符串[]args)引发异常
{
setProperty(“nashorn.args”,“--no-java-doe-ot=false--language=es6--no-deprecation warning--lazy compilation=false”);
for(长i=0;真;+i)
{
final ScriptEngine ScriptEngine=new ScriptEngineManager().getEngineByName(“nashorn”);
put(“JsJavaUtil”,新的JsJavaUtil());
eval(“for(var i=0;i<10;++i){\n”+“JsJavaUtil.testFunc();\n”+“}”);
gc();
如果(i%100==0)
{
System.out.println(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freemory());
}
}
}
}
运行此命令将导致转储约6-7MB无法访问的java.lang.ClassValue$ClassValueMap


我在寻找一些提示,是什么让这些物体保持了活力。

我不知道发生了什么,但它给出了一些有趣的发现。 快照比较-加载堆转储1、加载堆转储2、运行 “通过快照比较确定泄漏嫌疑人 :包括泄漏嫌疑犯 以及比较两个快照的系统概述。”

问题疑犯1

由“”加载的“java.lang.ClassValue$ClassValueMap”的一个实例占用+809280(19.48%)字节。内存累积在一个“java.lang.ClassValue$ClassValueMap”实例中,由“”加载,占用+809280(19.48%)字节

关键词 java.lang.ClassValue$ClassValueMap

此外,该报告还指出:

弱参考统计

总共找到了10007个java.lang.ref.WeakReference对象,它们弱引用了6969个对象。 6总计192 B的对象仅通过弱引用保留(保持活动)。 可能的内存泄漏总计124.4KB的5785个对象被弱引用,并且通过弱引用被强保留(保持活动)


详细情况»

我不知道发生了什么,但报告给出了一些有趣的发现。 快照比较-加载堆转储1、加载堆转储2、运行 “通过快照比较确定泄漏嫌疑人 :包括泄漏嫌疑犯 以及比较两个快照的系统概述。”

问题疑犯1

由“”加载的“java.lang.ClassValue$ClassValueMap”的一个实例占用+809280(19.48%)字节。内存累积在一个“java.lang.ClassValue$ClassValueMap”实例中,由“”加载,占用+809280(19.48%)字节

关键词 java.lang.ClassValue$ClassValueMap

此外,该报告还指出:

弱参考统计

总共找到了10007个java.lang.ref.WeakReference对象,它们弱引用了6969个对象。 6总计192 B的对象仅通过弱引用保留(保持活动)。 可能的内存泄漏总计124.4KB的5785个对象被弱引用,并且通过弱引用被强保留(保持活动)

详情»