【发布时间】:2010-10-18 15:12:40
【问题描述】:
如果我有:
for (int i; i != 100; i++) {
ArrayList<String> myList = buildList();
//... more work here
}
我是否必须在循环结束时将 myList 设置为 null 才能让 GC 回收它用于 myList 的内存?
【问题讨论】:
如果我有:
for (int i; i != 100; i++) {
ArrayList<String> myList = buildList();
//... more work here
}
我是否必须在循环结束时将 myList 设置为 null 才能让 GC 回收它用于 myList 的内存?
【问题讨论】:
GC 会自动清理所有不再在作用域内的变量。
在块中声明的变量,例如 for 循环,将只在该块的范围内。代码退出块后,GC 将删除它。一旦循环的迭代结束,就会发生这种情况,因此,只要循环的每次迭代结束,列表就可以进行垃圾回收。
变量的范围也是为什么i 在示例循环之后无效的原因。
请注意,只有在循环中使用变量时才会出现这种情况。如果你将它传递给另一个保留对它的引用的方法,你的变量将不会被垃圾回收。
【讨论】:
myList 的对象将被GC'd,即使仍在循环中。不是在循环之后。
i无关,那是一个原始的栈变量,不是堆上的实例。
主啊,不! Java 的 GC 比这要智能得多,much,much。
【讨论】:
buildList() 的结果覆盖finalize(),那将是灾难性的。但让我们希望代码是理智的。
finalize() 的愚蠢实现的一般警告,无论是否在循环中.那么简单地覆盖finalize() 是如何导致灾难性结果的呢?
GC 会在需要时回收所有无法访问的实例。它没有 GC 变量。
变量i 和myList 存在于堆栈中。当 for 循环结束时(当它们超出范围时),它们将被压出堆栈,因此它们的内存被回收。然后变量将消失。在引用变量 myList 消失之前将其设置为 null 确实没有什么区别(对于 GC 实例)。如果 GC 也会为引用的实例 myList 回收内存,这实际上取决于您是否有另一个对同一实例的引用。
变量不会被 GC,实例会。
【讨论】:
这可能有助于理解 for 循环背后的语法。这在JLS Section 14.14.1 中进行了讨论。
BasicForStatement: for ( ForInitopt ; Expressionopt ; ForUpdateopt ) Statement ... Statement: StatementWithoutTrailingSubstatement ... StatementWithoutTrailingSubstatement: Block EmptyStatement ExpressionStatement ... Block: { BlockStatementsopt } BlockStatements: BlockStatement BlockStatements BlockStatement BlockStatement: LocalVariableDeclarationStatement ClassDeclaration Statement
语句,一如既往,可以是单个语句或块(用花括号括起来的语句)。一个块代表一个新的词法范围,其中声明的变量仅对该块是本地的。许多人没有意识到这并不是 for 循环所独有的。我可以在方法中的任何位置放置块语句:
public void someMethod() {
{
List<String> myList = new ArrayList<String>();
System.out.println(myList);
}
System.out.println(myList.size()); //compile error: myList out of scope
}
无论如何,这并不符合我的预期。可以说它与它是一个循环的事实关系不大,而与它是一个块的事实有关(如果你选择不使用块语句,你不能声明新的局部变量,所以问题是无关)。
【讨论】:
您不必为垃圾烦恼。 Java GC 会自动执行此操作。 但我的建议是,作为一名优秀的开发人员,你必须进行实践 用于释放垃圾。 因为 GC 需要一些处理时间。 因此,通过照顾好自己,我们肯定会提高性能。
【讨论】: