我遇到这样的代码:
{
final List myTooBigList = new ArrayList();
... overfill the list
}
somethingRunOutOfMemory();
somethingRunOutOfMemory(),因为myTooBigList不GCable,尽管不在范围内了。
和C一样,局部变量位于堆栈旁边。 堆栈指针为scope中的局部变量保留了所需的空间。 堆栈重用时,块的局部变量变为GCable。 当超出范围时,指针立即根据新的本地变量移回。
他们GCable后:
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
他们不是GCable后:
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
如果我想有一个地方是GCable我写:假的
{
final List myTooBigList = new ArrayList();
... overfill the list
}
Object fake = null;
somethingDoesntRunOutOfMemory();
矫揉造作将堆栈指针移回并使myTooBigList GCable。令人惊讶的是(至少在我测试的jvm中)我们必须明确地重用堆栈。一旦块被退出,预计局部变量会变成GCable,但我想这是对性能的妥协。这会使字节码复杂化很多。
注意:要测试一个变量是否为GCable,我运行GC,然后将WeakReference(我的变量)与null进行比较。
final WeakReference gctest;
{
final List myTooBigList = new ArrayList();
gctest = new WeakReference(myTooBigList);
... overfill the list
}
Object fake = null;
System.gc();
assert gctest.get() == null;
在之前的实现中,直到方法结束才会真正持久化?这将是一种奇怪的... – 2010-11-09 20:25:58
@ Erick:我更努力避免*未来*实现将保留本地变量作为“根”的保证。 .NET CLR绝对不会,实际上一个对象可以被垃圾回收*,而一个实例方法仍然在执行“in”它*,只要GC知道什么都不会引用它的任何字段。 – 2010-11-09 20:27:14
@Erick如果'doSomething()'不使用对象的任何其他字段或方法,或者可以将JIT编码以便将所有字段放入寄存器并将所有方法内联,则可以在' doSomething()'完成,更不用说'myFunction()'。唯一的标准是代码的含义是否改变。 – 2010-11-09 20:32:20