垃圾收集哪个对象?

时间:2010-01-20 06:03:20

标签: java garbage-collection

我想确认哪个场景会导致对象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是否会改善垃圾收集行为,或者在使用新构造函数重置对象时是否相同?

4 个答案:

答案 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实例只有一个“副本”。顺序是:

  1. 您创建一个MyObject实例,并将其引用分配给myObj

  2. 您将实例的引用添加到arList引用的ArrayList。

  3. 您将null分配给myObj中的参考。

  4. 请注意,添加对列表的引用不会创建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);  
}