java 局部变量上的垃圾收集
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4138200/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Garbage collection on a local variable
提问by Espen
I'm a C++ programmer entering the world of Java. And I cannot get rid of the bad feeling of having to let the Java garbage collector do my cleaning.
我是一名进入 Java 世界的 C++ 程序员。而且我无法摆脱不得不让 Java 垃圾收集器进行清理的糟糕感觉。
How, for example, will this code behave in Java?
例如,这段代码在 Java 中的表现如何?
public void myFunction() {
myObject object = new myObject();
object.doSomething();
}
Will the local variable object be deleted when myFunction() exits?
myFunction() 退出时局部变量对象会被删除吗?
Do I have to set object to null before exiting, or will it be out of scope and be deleted by the GC? Or, at worst, will it leak like it would in C++?
我是否必须在退出之前将对象设置为 null,否则它会超出范围并被 GC 删除?或者,在最坏的情况下,它会像在 C++ 中一样泄漏吗?
回答by Jon Skeet
It will be garbage collected at some point after it's no longer used. I believe in current implementations of Java it will actually persist until the end of the method, whereas the garbage collector in .NET is more aggressive. (I don't know whether there are any guarantees even in Java. Normally you'd only wantthe local variable to persist beyond its last possible read when you're debugging.)
它将在不再使用后的某个时候被垃圾收集。我相信在 Java 的当前实现中,它实际上会持续到方法结束,而 .NET 中的垃圾收集器更加激进。(我不知道即使在 Java 中是否有任何保证。通常情况下,您只希望局部变量在调试时持续超过其最后一次可能的读取时间。)
But no, you don't need to set the variable to null, and doing so would harm readability.
但是不,您不需要将变量设置为 null,这样做会损害可读性。
It's unlikely that the object will garbage collected immediatelyafter the method exits; it's up to when the GC runs... and of course if anything else holds onto a reference to the object, it may not be eligible for garbage collection anyway. Don't forget that the value of the variable is just a reference, not the object itself. (That may take a while to get used to coming from C++.)
对象不太可能在方法退出后立即被垃圾回收;这取决于 GC 何时运行……当然,如果有其他任何东西保留了对该对象的引用,则无论如何它都可能不符合垃圾收集条件。不要忘记变量的值只是一个引用,而不是对象本身。(这可能需要一段时间才能习惯来自 C++。)
回答by Thibault LE PAUL
GC does the job at least when memory limit approaches, since any object referenced by out-of-scope variables can be garbage collected, but there is an unexpected behavior of out-of-scope local variables of the last exited block.
GC 至少在内存限制接近时完成这项工作,因为范围外变量引用的任何对象都可以被垃圾收集,但是最后一个退出块的范围外局部变量会出现意外行为。
To look under the hood, let us compare :
为了深入了解,让我们比较一下:
{
final List myTooBigList = new ArrayList();
... overfill the list
}
somethingRunOutOfMemory();
somethingRunOutOfMemory()
because myTooBigList
were not GCable, despite not in scope anymore and more memory was claimed, unlike the following :
somethingRunOutOfMemory()
因为myTooBigList
不是 GCable,尽管不再在范围内并且声明了更多内存,与以下不同:
{
final List myTooBigList = new ArrayList();
... overfill the list
}
Object fake = null;
somethingDoesNotRunOutOfMemory();
Affectation of fake
moves the stack pointer back and let myTooBigList
GCable, then GC does its work as soon as memory limit approaches.
The surprise is that (at least in the jvm I'm testing) we have to explicitely reuse stack at the same level. It would be expected that local variables be GCable as soon as the block is exited, but I guess it's a compromise with performance. It would complicate much the bytecode.
Affectationfake
将堆栈指针移回并让myTooBigList
GCable,然后 GC 会在内存限制接近时立即执行其工作。令人惊讶的是(至少在我正在测试的 jvm 中)我们必须在同一级别明确重用堆栈。一旦块退出,局部变量应该是可GCable的,但我想这是对性能的妥协。它会使字节码复杂化。
Like in C, local variables are located in stack beside frames. The stack pointer reserves as much space as required for the local variables in scope. Local variable of an { exited block } become GCable when stack is reused, that is: after a local variable is declared at the same stack level, after the function returns, or after an exit evaluation (catch, loop condition).
像在 C 中一样,局部变量位于帧旁边的堆栈中。堆栈指针为作用域中的局部变量保留了所需的空间。{ exited block } 的局部变量在堆栈被重用时变为可GCable,即:在同一堆栈级别声明局部变量后,函数返回后,或退出评估(catch,循环条件)后。
They are GCable after :
他们是 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
{ } declare=value : after any declaration+affectation that reuses stack
They are not GCable just after :
他们不是 GCable 之后:
try { } : after nothing caught
for { } : after exit by break
while { } : after exit by break
do { }
if { }
{ }
NOTE : for a lab, run GC then compare a WeakReference(my variable)
to null
.
注意:对于实验室,运行 GC 然后将 aWeakReference(my variable)
与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;
回答by Hannes de Jager
It will go out of scope. In Java, when no-one is pointing to an object anymore, it will be garbage collected or at least it will be available for garbage collection. No need to set it to null here. Sometimes setting an object reference to null is needed if your object will live on in you App, but a reference it holds needs to be garbage collected. In this case you are choosing to release the reference.
它将超出范围。在 Java 中,当没有人再指向某个对象时,它将被垃圾回收,或者至少可以用于垃圾回收。无需在此处将其设置为 null。有时,如果您的对象将存在于您的 App 中,则需要将对象引用设置为 null,但它持有的引用需要被垃圾收集。在这种情况下,您选择释放引用。