我想确认哪个场景会导致对象myObj上的垃圾收集:
情景1
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
}
场景2
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
myObj=null;
}
将对象显式设置为null是否会改善垃圾收集行为,或者在使用新构造函数重置对象时是否相同?
答案 0 :(得分:7)
您没有指定myObj
的范围及其重要性。如果它是一个局部变量,它几乎肯定无关紧要。如果它是一个实例变量,那么这可能是一个长期存在且不必要的引用,在这种情况下设置为null
将是有用的。
更新:根据myObj
方法的本地更新信息,在每次迭代结束时将其设置为null
为零值循环。考虑这个例子:
public void process(String text) {
String[] lines = text.split("\n");
List<MyObject> list = new ArrayList<MyObject>();
Object myObj;
for (String line : lines) {
myObj = new MyObject(line);
list.add(myObj);
// 1. set myObj = null here
}
list = null; // 2
// 3. do some other stuff
}
public class MyObject {
private final String line;
public MyObject(String line) {
this.line = line;
}
}
现在在这个例子中,让我们说在第3步,花了很长时间。说10分钟。在那10分钟内,myObj
指向处理的最后一行。听起来不是什么问题?好吧,它可能是。子串在Java中的工作方式是它们引用原始字符串。所以如果你这样做:
String s = ... // 100 megabytes
String s2 = s.substring(100, 101);
你实际上将整个100MB保留在内存中,因为s2引用s。
因此,在上面的函数中,myObj
引用了引用整个文件的行。将步骤1更改为myObj = null;
实际上会有所帮助,因为此引用会阻止对象被垃圾回收。
注意:第2步在这里很重要,因为如果你没有使列表无效,那么所有引用都会存在。
您只需要考虑引用的工作原理。当对象存在时,对象不会被垃圾收集。这意味着清除长寿命引用并尽可能保持变量范围。上述的正确解决方案是:
for (String line : lines) {
Object myObj = new MyObject(line);
...
}
然后myObj
在循环中作用域,所以一旦循环结束或另一次迭代开始,它就超出了范围,很多更好。
答案 1 :(得分:6)
将其设置为null
将无效,因为该对象仍然是reachable来自arList
。
也就是说,您的MyObect
个实例的有效期至少与arList
一样长。
编辑:根据您的评论,它听起来像myObj
的寿命更长。在这种情况下,请在循环结束后将其设置为null
。
答案 2 :(得分:2)
我认为这是你误解的根源。
嗯..但是我不想保留myObj的2个副本,一个在arList中,一个在原始变量中。一旦我将它添加到arLsit,我如何刷新myObj?
你不要“保留myObj的两份副本”。在您的示例中,循环创建的每个MyObject实例只有一个“副本”。顺序是:
您创建一个MyObject实例,并将其引用分配给myObj
。
您将实例的引用添加到arList
引用的ArrayList。
您将null
分配给myObj
中的参考。
请注意,添加对列表的引用不会创建MyObject实例的副本。它只是意味着您在两个地方而不是
一。当您分配null
时,您再次在一个地方获得了参考。
另一件需要注意的事情是,将null
分配给某些内容永远不会导致垃圾收集器运行。它所做的只是(明确地)在下次运行垃圾收集器时从中考虑删除引用的潜在副本。
最后,如果我们假设范围如下,那么C行将没有明显的效果...... 除非 A行或B行触发垃圾收集。
{
MyObject myObj;
ArrayList arList = new ArrayList();
while (someCondition) { // A
myObj = new MyObect(); // B
arList.add(myObj);
myObj = null; // C
}
}
答案 3 :(得分:1)
因为它位于while
,所以myObj
总是被覆盖(引用)。因此,在场景1中,只有一个对象(arList
中添加的最后一个)不是null
。
如果你在while
声明中声明它会更好:
while(someCondition)
{
MyObect myObj = new MyObect(); // a custom object
arList.add(myObj);
}