代码之家  ›  专栏  ›  技术社区  ›  Espen

总司令要走多远

  •  3
  • Espen  · 技术社区  · 14 年前

    Java GC将走多远?假设我有这个代码:

    public class MyClass {
        private Object myObject = new Object();
        public void clear() {
            myObject = null;
        }
    }
    
    public class MyMain {
        ...
        MyClass myClass = new MyClass();
        ...
        myClass.clear();
        myClass = null;
    }
    

    在将myClass设置为null以确保GC将删除myClass中的myObject之前,是否需要调用myClass.clear()?或者仅仅将myClass设置为null,GC就可以删除所有嵌套对象吗?

    也许我有点偏执,答案很简单,“GC最终会删除任何运行的代码或任何将来可用的代码无法访问的对象”。因此,如果一个已创建的对象不可用,或者永远不可用,在任何运行的代码中,它最终会成为GC的受害者,甚至认为它是嵌套的,并使C++程序员感到害怕。

    9 回复  |  直到 14 年前
        1
  •  9
  •   Jon Skeet    14 年前

    不,你不需要打电话 myClass.clear() . 当无法通过实时引用访问对象时,它将有资格进行垃圾收集。这并不意味着它会马上被收集,但它会 合格的 收藏。

    它是 非常 很少适合为了垃圾收集而将引用设置为null,这样做会损害代码的可读性。当然,也有例外,例如, ArrayList<T> 将其内部缓冲区的元素设置为 null 当不再需要时,为了避免意外地阻止对象被垃圾收集,但通常只要对象本身是必需的,对象中的字段就有效且有用。总之,我几乎从来没有 像这样的方法 MyClass.clear() ,更别说叫它了。

    很少有必要将局部变量设置为空。你的代码 MyMain 不清楚,因为它在方法外无效。。。如果你是说 全部的 方法中的代码,则不需要设置 myClass 也为空。当方法完成时,变量将不再作为它引用的对象的GC根来贡献-当然,如果 其他 GC根存在,对象仍然不适合垃圾收集。但是,在方法末尾将局部变量设置为空是没有意义的。

        2
  •  8
  •   Matt Ball    14 年前

    你没有 需要 设置 任何东西 为了让它成为GC'd而设为空。不要妄想。

    不要试图像C++那样编程Java。

        3
  •  7
  •   Eyal Schneider    14 年前

    很少真正需要“帮助”gc完成引用空操作。

    以下是一个人工情况,在这种情况下,空值确实有帮助:

        long[] arr = new long[7000000];
        //arr = null;
        arr = new long[7000000];
    

    如果使用-Xmx100M运行此命令,它将失败,并显示OutOfMemoryError。如果取消注释使arr为空的行,它将正常工作。发生这种情况是因为arr引用在创建另一个数组时仍然保留着这个巨大的数组。内存分配发生在分配之前,它触发垃圾回收,并且失败。当取消引用时,GC会成功地生成足够的空间。

        4
  •  2
  •   T.J. Crowder    14 年前

    不,你不需要打电话 clear 第一。GC会很高兴地找到未使用的 myObject 引用并回收它。

    实际上,GC可以处理非常复杂的对象图,包括循环引用:

    public class Foo
    {
        public HashMap a;
        public HashMap b;
    
        public Foo() {
            a = new HashMap();
            b = new HashMap();
            a.put("b", b);
            b.put("a", a);
        }
    }
    // ...
    public void someFunction() {
       Foo f = new Foo();
    }
    

    (我通常不会 a b 公众,但我在这里尽量表现得极端。)

    你不需要清理 f ,或 ,或 . 如果没有引用 f型 ,最终 f型 将检查可达性,并且GC不会对以下事实有任何问题 相互参照。

    细节 (很多细节) 在里面 the JLS .

        5
  •  1
  •   cHao    14 年前

    是的,你太偏执了。只要一个对象不能通过运行代码来达到,它最终将被收集(虽然“最终”)可能意味着“当程序退出时,如果有足够的内存和GC不需要运行”。不可访问对象中的引用也不可访问,因此就GC而言,它们不再计数。

    不过,请注意,这意味着 finalize 可能已经在子对象中运行,因此如果要在终结器中执行任何工作,就不能依赖任何不是基元的子对象。

        6
  •  0
  •   JonH    14 年前

    GC最终将正确地处理对象。我觉得你可能有点偏执。尽管将对象设置为空不会造成伤害。

    如果您调用了myObject.clear来回答您的问题,它只会使myObject=null,那么没有理由再次将其重置为null。

        7
  •  0
  •   Jim    14 年前

    您甚至不需要将myclass设置为空。一旦超出范围,就有资格进行垃圾收集。

        8
  •  0
  •   cadolphs    14 年前

    GC将处理所有与它无关的内容。所以,在 MyClass 已处理,将不会留下对 myObject 因此,它将被GC移除

        9
  •  0
  •   OscarRyz    14 年前

    在将myClass设置为null以确保GC将删除myClass中的myObject之前,是否需要调用myClass.clear()?

    你不必打电话给clear,也不必设置 myClass 为空。

    您也不能确定它是否会被收集,但是如果VM需要内存,那么当 我的阶级 它本身是不可参照的。

    所以在这种情况下你不必担心。