Sun 15 Feb 2009 10:26:34 PM UTC, original submission:
Tested with kawa-1.9.1.
A memory leak occurs within the CallContext class:
test/Test.java:
package test;
import kawa.standard.Scheme;
public class Test
{
public static void main(String[] args)
{
Scheme.registerEnvironment();
byte[] bytes = new byte[240 * 1024 * 1024];
System.out.println("(main) length: " + bytes.length);
new TestKawaSimpleClass().printArrayLength(bytes);
bytes = null; //allow garbage collect
bytes = new byte[240 * 1024 * 1024];
System.out.println("(main) length: " + bytes.length);
}
}
test/TestKawa.scm:
(module-name <test.TestKawa>)
(module-static 'init-run)
(module-export print-length)
(define-simple-class <TestKawaSimpleClass> (<Object>)
((printArrayLength (array :: <byte[]>)) :: void
(print-length array)))
(define (print-length (array :: <byte[]>)) :: void
(format #t "(print-length) length: ~a~%" (field array "length")))
Compile Test.java w/ javac. Compile TestKawa.scm with --full-tailcalls option:
Running with 256M of heap (java -Xmx256M), I get the following:
(main) length: 251658240
(print-length) length: 251658240
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at test.Test.main(Test.java:27)
The OutOfMemory error is unexpected because the first byte array should not be [strongly] referenced at this point and should be garbage-collected.
Recompiling --no-full-tailcalls option, I get:
(main) length: 251658240
(print-length) length: 251658240
(main) length: 251658240
which is the expected behaviour. So the problem must be related to usage of CallContext.
What happends is that the first byte array is still referenced by the value1 field of CallContext as shown by the following output of jhat (heap analysis tool):
Java Local Reference (from java.lang.ref.Reference$ReferenceHandler@0xa44fbba0) :
--> java.lang.ref.Reference$ReferenceHandler@0xa44fbba0 (104 bytes) (field group:)
--> java.lang.ThreadGroup@0xa44f85c0 (43 bytes) (field groups:)
--> [Ljava.lang.ThreadGroup;@0xa44fbc58 (24 bytes) (Element 0 of [Ljava.lang.ThreadGroup;@0xa44fbc58:)
--> java.lang.ThreadGroup@0xa44f8590 (43 bytes) (field threads:)
--> [Ljava.lang.Thread;@0xa44fbca8 (24 bytes) (Element 0 of [Ljava.lang.Thread;@0xa44fbca8:)
--> java.lang.Thread@0xa44fbcc8 (104 bytes) (field threadLocals:)
--> java.lang.ThreadLocal$ThreadLocalMap@0xa44fbd60 (20 bytes) (field table:)
--> [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;@0xa44fbd78 (72 bytes) (Element 1 of [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;@0xa44fbd78:)
--> java.lang.ThreadLocal$ThreadLocalMap$Entry@0xa4517bd0 (28 bytes) (field value:)
--> gnu.mapping.CallContext@0xa4517bf0 (76 bytes) (field value1:)
--> [B@0x954e0000 (251658248 bytes)
Note that a similar problem can arise with the vstack field when using multiple values. In fact, we originally found it there.
We are using web applications under a webapp server and since it probably uses a thread pool for request handling, the problem can exist on each idle thread.
|