代码之家  ›  专栏  ›  技术社区  ›  Natalie Perret

当数组进行垃圾回收时?

  •  2
  • Natalie Perret  · 技术社区  · 6 年前

    几年前我读了一本书《通过C实现CLR》,前几天我被问到是否有一个数组,但还是有点困惑,问题是要弄清楚下面方法中的数组何时可以用于垃圾收集:

    public static double ThingRatio()
    {
        var input = new [] { 1, 1, 2 ,3, 5 ,8 };
        var count = input.Length;
        // Let's suppose that the line below is the last use of the array input
        var thingCount = CountThings(input);
        input = null;
        return (double)thingCount / count;
    }
    

    根据这里给出的答案: When is an object subject to garbage collection? 其中规定:

    一旦不符合条件,他们都将有资格领取 不再需要了。这意味着在某些情况下,对象可以 定义。另一方面,实际收集也可能发生

    input = null; )数组将受到GC的影响,但我不确定(我的意思是数组在任务完成后肯定不再需要了,但是在任务完成后它仍然在挣扎 CountThings 调用,但同时数组对于空赋值是“必需的”。

    3 回复  |  直到 6 年前
        1
  •  6
  •   Joel Coehoorn    6 年前

    记住,对象和变量不是一回事。A. 对特定的方法或类型有作用域,但它所指或用来指的对象没有这样的概念;只是一团记忆。如果GC在 input = null; 但是在方法结束之前,数组只是一个孤立的对象。不是的 可达成的 ,因此有资格领取。

    “可达”(而不是“需要”)是这里的关键词。此行之后不再需要数组对象: var thingCount = CountThings(input); . 但是,它仍然是可以到达的,所以不能在那个时候收集。。。

    我们还需要记住,它不是立即收集的。只是 待收集。作为一个实际问题,我发现.NET运行时不倾向于在用户方法的中间调用GC,除非它真的必须如此。 null 在一些罕见的情况下甚至可能是有害的。

        2
  •  4
  •   rickvdbosch    6 年前

    GC谬论:将对象的引用设置为null将强制GC立即收集它。
    gctruth:将对象的引用设置为null有时会允许GC更快地收集它。

    把我在下面引用的博文的一部分应用到你的问题中,答案如下:

    JIT通常非常聪明,能够意识到这一点 input = null 可以优化掉。就这样离开了 CountThings(input) input 不再使用,作为GC根被删除。这会使内存中的对象成为孤立对象(没有指向它的引用),从而使其符合收集条件。当GC真正开始收集它时,这是另一回事。

    更多信息请访问 To Null or Not to Null

        3
  •  3
  •   supercat    6 年前

    请注意,有些源混淆了对象终结器的触发与垃圾回收,但终结器被触发的对象保证至少在终结器执行所需的时间内继续存在,并且如果终结器完成执行时存在对它的任何引用,则该对象可能会无限期地继续存在。

    CountThings 对于传入的引用:

    1. 如果 不将引用的副本存储在任何位置,或者它存储的引用的任何副本在此之前被覆盖 input 如果被覆盖,那么它将在 被覆盖或不再存在[自动持续时间变量可能在编译器确定不再观察其值时不再存在]。

    2. 如果

    3. 如果最后一个存在的引用数组最终被保存在一个弱引用中,那么数组将继续存在,直到第一个GC循环,在这种情况下,弱引用将被清除,从而导致数组停止存在。请注意,缺少对数组的非弱引用仅在GC循环发生时才相关。程序将引用的副本存储到 WeakReference ConditionalWeakTable ,或持有某种形式的弱引用的其他对象,销毁所有其他副本,然后在下一个GC循环之前读取弱引用以生成引用的非弱副本。如果发生这种情况,系统将既不知道也不关心曾经存在过引用的非弱副本。但是,如果GC循环发生在读取引用之前,那么稍后检查弱引用的代码将发现它为空。

    一个关键的观察结果是,虽然终结器和弱引用稍微使事情复杂化,但GC销毁对象的唯一方法是使弱引用形式无效。就GC而言,当系统没有实际执行GC循环时,唯一存在的存储类型是由存在的对象使用的存储类型、用于.NET内部目的的存储类型以及可用于满足未来分配的存储区域。如果创建了一个对象,它所占用的存储将不再是可供将来分配的存储区域。如果该对象后来不再存在,则 存储 包含该对象的对象也将不再以GC知道的任何形式存在,直到下一个GC周期。下一个GC周期不会销毁对象(它已经不存在了),而是将包含它的存储添加回可用于添加未来分配的区域列表(使该存储再次存在)。