Java Memory leak: Why are unreachable objects not collected?

1.6k Views Asked by At

I am trying to find a workaround for the JDK Nashorn bug JDK-8229011.

I reproduced the error with the script linked in the bug ticket and took several heap dumps. I used JProfiler and Eclipse Memory Analyzer to find the root of the problem. But, I always end up in unreachable paths and I don't understand why the objects are not garbage collected. AFAIS there are no finalizers to keep them alive. If I open the heap dump in JProfiler without disabling "Full GC on Dump", JProfiler will even throw the unreachable objects away. But the GC itself won't. I tested with G1 GC, but its the same with CMS.

You can get a sample dump in 1-2 minutes with any JDK > 8 by running the following script with the settings: -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());
            }
        }
    }
}

Running this will lead to a dump with an about 6-7 MB of unreachable java.lang.ClassValue$ClassValueMap

I am looking for some hints, what is keeping these objects alive.

1

There are 1 best solutions below

0
user13762112 On

I don't know what is going on, but the latest development build of Eclipse Memory Analyzer gives some interesting findings. Snapshot comparison - load heap dump 1, load heap dump 2, run "Leak Suspects by Snapshot Comparison : includes leak suspects and a system overview from comparing two snapshots."

Problem Suspect 1

One instance of "java.lang.ClassValue$ClassValueMap" loaded by "" occupies +809,280 (19.48%) bytes. The memory is accumulated in one instance of "java.lang.ClassValue$ClassValueMap", loaded by "", which occupies +809,280 (19.48%) bytes.

Keywords java.lang.ClassValue$ClassValueMap

Also Component report says:

Weak Reference Statistics

A total of 10,007 java.lang.ref.WeakReference objects have been found, which weakly reference 6,969 objects. 6 objects totalling 192 B are retained (kept alive) only via weak references. Possible Memory Leak 5,785 objects totalling 124.4 KB are weakly referenced and also strongly retained (kept alive) via weak references.

Details »