Export to GitHub

google-collections - issue #308

MemoryLeak(?) when using expiration in MapMaker


Posted on Dec 14, 2009 by Happy Elephant

Expected: Using "public MapMaker expiration(long duration, TimeUnit unit)" should not influence garbage collection.

Observed: In one of my junit tests, test case A asserts that an OutOfMemoryError is thrown under special circumstances when MapMaker and expiration are used. Test case B, which is executed after A and does something different with a new map instance, unexpectedly fails with OOME. This means the memory allocated in test case A was not released, even though no fields are used and an new map instance is created. If expiration is not used, all works as expected.

I tried to reproduce the same effect in a smaller test case, but did not succeed. Instead expecting an OOME already fails (with an OOME). Looking at the stacktrace, the junit code executed after a test, runs into an OOME (which also indicates, that the memory allocated in the test is not released).

Stacktrace: java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Arrays.java:3209) at java.lang.String.<init>(String.java:216) at java.lang.StringBuilder.toString(StringBuilder.java:430) at java.net.URLStreamHandler.parseURL(URLStreamHandler.java:232) at sun.net.www.protocol.file.Handler.parseURL(Handler.java:50) at java.net.URL.<init>(URL.java:596) at java.net.URL.<init>(URL.java:464) at sun.misc.URLClassPath$FileLoader.getResource(URLClassPath.java:973) at sun.misc.URLClassPath.getResource(URLClassPath.java:168) at java.net.URLClassLoader$1.run(URLClassLoader.java:192) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:252) at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320) at org.junit.internal.runners.model.EachTestNotifier.addFailure(EachTestNotifier.java:29) at org.junit.runners.ParentRunner.run(ParentRunner.java:226) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:46) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Attachments

Comment #1

Posted on Dec 14, 2009 by Happy Elephant

This also seems to destroy the semantic of weakValues().

To reproduce:

  1. Remove "(expected = OutOfMemoryError.class)" from the test case.

2.a. remove expiration() and and add weakValues() ConcurrentMap map = new MapMaker().weakValues().makeMap(); Observed: Works, no OOME.

2.b. Leave expiration() in place and add weakValues() ConcurrentMap map = new MapMaker().weakValues().expiration(3600, TimeUnit.SECONDS).makeMap(); Observed: OOME (even though weakValues() was used!) What is more the number of entries that can be stored in this way does not differ much from not using weakValues() at all. In my test the combination weakValues/expiration adds ~ 550K while a normal "new MapMaker().makeMap()"- map adds ~ 450K.

Comment #2

Posted on Jan 5, 2010 by Happy Wombat

This issue has been moved to the Guava project (keeping the same id number). Simply replace 'google-collections' with 'guava-libraries' in your address bar and it should take you there.

Status: Moved