Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6786318

MemoryCache leaks memory on repetative requests for the same resource

XMLWordPrintable

    • b04
    • generic, x86
    • generic, windows_xp
    • Verified

        If you, for example, try running the SmokeParticles sample from our public demo collection (http://javafx.com/samples/SmokeParticles/index.html) and let it sit
        in the browser for a while (you're reading the article), it will bring
        your system to its knees (or just keep burning all the spare CPU cycles,
        depending on how good your OS scheduler is).

        The problem is a memory leak in the JNLP infrastructure, namely in MemoryCache,
        together with this innocent and simple pattern used in the demo:
        return ImageView {
            image : Image { url: "{__DIR__}/../resources/texture.png" }
        };

        that is, creating (and properly freeing) many ImageViews from the same resource.

        The MemoryCache thing is unnecessarily complicated, it seems. It implements
        a reference counting scheme, trying to be smarter than the garbage collector
        and failing at it. Each call to getLoadedResource with the same (in fact equal,
        not the same) String leaks a CachedResourceReference and the mentioned String.
        (Please note that each time a new String instance is used, as it is constructed
        along the code path):
        com.sun.deploy.cache.MemoryCache.getLoadedResource(MemoryCache.java:78)
        com.sun.deploy.net.DownloadEngine.getResourceCacheEntry(DownloadEngine.java:1483)
        com.sun.deploy.net.DownloadEngine.getResourceCacheEntry(DownloadEngine.java:1436)
        com.sun.deploy.net.DownloadEngine.getCachedJarFile(DownloadEngine.java:457)
        com.sun.deploy.net.DownloadEngine.getCachedJarFile(DownloadEngine.java:434)
        com.sun.jnlp.JNLPClassLoader$3.run(JNLPClassLoader.java:434)
        java.security.AccessController.doPrivileged
        com.sun.jnlp.JNLPClassLoader.getJarFile(JNLPClassLoader.java:430)
        com.sun.jnlp.JNLPCachedJarURLConnection.connect(JNLPCachedJarURLConnection.java:160)
        com.sun.jnlp.JNLPCachedJarURLConnection.getInputStream(JNLPCachedJarURLConnection.java:203)
        java.net.URL.openStream
        com.sun.javafx.scene.image.ImageLoader.readImage
        com.sun.javafx.scene.image.ImageLoader.<init>
        javafx.scene.image.Image.initialize$impl
        javafx.scene.image.Image.initialize
        javafx.scene.image.Image.postInit$
        javafx.scene.image.Image.initialize$
        particles.Particle.create$impl(Particle.fx:33)
        particles.Particle.create(Particle.fx:20)
        [...]

        I have a dump from the point where the GC was scraping for the last free bits
        out of 64MB default heap. Bzipped it is 8.5MB.
        But it boils down to (for single resource):
        MemoryCache.loadedResource map having an entry (LoadedResourceReference)
        strong*1 holding the object (CacheEntry) and a big set of WeakReferences
        (CachedResourceReferences) to the same CacheEntry.
        MemoryCache was probably intended to remove the entry from the map
        once all the WeakReferences die, but:
        1. that would never happen (because of *1)
        2. all would die at once anyway, no need to have 200.000 of them.
        Simplified testcase:

        import com.sun.deploy.cache.MemoryCache;

        public class Test {
            public static void main(String[] args) throws Exception {
                String u = "http://localhost/";
                Object o = new int[100000]; //make it large to detect object leak
                Object junk;

                System.out.println("Total Memory"+Runtime.getRuntime().totalMemory());
                MemoryCache.addLoadedResource(u, o);
                for(int i=0; i<1000000; i++) {
                    junk = MemoryCache.getLoadedResource(u);
                }
                System.err.println("Done");
            }
        }

              igor Igor Nekrestyanov (Inactive)
              igor Igor Nekrestyanov (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: