I came across this code:
{ final List myTooBigList = new ArrayList(); ... overfill the list } somethingRunOutOfMemory();
somethingRunOutOfMemory () because myTooBigList was not a GCable even though it was no longer in scope.
As in C, local variables are stacked next to frames. The stack pointer reserves as much space as is needed for local variables in scope. The local block variable becomes GCable when the stack is reused. When a pointer moves out of scope, as soon as it is required by new local variables.
They are GCable after:
try { } catch : after exit by catch because catch reuses stack for { } : after exit loop condition because evaluation reuses stack while { }: after exit loop condition because evaluation reuses stack { } followed by any local declaration that reuses stack
They are not GCable after:
try { } finally try { } catch : after nothing caught for { } : after break while { } : after break do { } while : after loop condition if { } { } not followed by a local declaration
If I want local to be GCable, I write:
{ final List myTooBigList = new ArrayList(); ... overfill the list } Object fake = null; somethingDoesntRunOutOfMemory();
Fake affectation moves the stack pointer back and makes myTooBigList GCable. Surprisingly, (at least in jvm testing) we must explicitly use the stack. It would be more expected that the local variables will be GCable as soon as they exit the block, but I think this is a compromise with performance. This will complicate the bytecode.
NOTE. To check if the variable is GCable, I run GC, then compare the value of WeakReference (my variable) to zero.
final WeakReference gctest; { final List myTooBigList = new ArrayList(); gctest = new WeakReference(myTooBigList); ... overfill the list } Object fake = null; System.gc(); assert gctest.get() == null;
Thibault LE PAUL Sep 21 '14 at 15:35 2014-09-21 15:35
source share