C#Action,Closure和Garbage Collection

时间:2011-11-17 16:28:34

标签: c# garbage-collection closures

我是否需要将MyAction设置为null,以便垃圾收集能够继续使用这些类中的任何一个?

当两个班级的生命周期几乎相同时,我不太关心。当Class1的寿命比Class2长得多或者Class2的寿命比Class1长得多时,我的问题更合适。

此处的代码已被删除。假设Class1和Class2都包含可能影响其生命周期的其他成员和方法。

public class Class1 : IDisposable
{
    public Action<string> MyAction { get; set; }

    // Is this necessary?
    public void Dispose()
    {
        MyAction = null;
    }
}

public class Class2
{
    string _result = string.Empty;

    public void DoSomething()
    {
        Class1 myClass1 = new Class1();
        myClass1.MyAction = s => _result = s;
        myClass1.Dispose();
    }
}

4 个答案:

答案 0 :(得分:18)

  

我是否需要将MyAction设置为null,以便垃圾收集能够继续使用这些类中的任何一个?

没有。任何时候你“管理”托管资源,你可能做错了。让垃圾收集器完成它的工作。

  

当两个班级的生命周期几乎相同时,我不太关心。当Class1的寿命比Class2长得多或者Class2的寿命比Class1长得多时,我的问题更合适。

这个问题没有任何意义; classes 没有生命周期存储地点有生命周期。您担心哪些存储位置?你能澄清这个问题吗?

我注意到,通过封闭延长封闭变量的寿命存在非常严重的问题;然而,你的问题是如此模糊,以至于很难理解你是否遇到了这样的情况。让我演示一下:

class Expensive
{
    public byte[] huge = MakeHugeByteArray();
}

class Cheap
{
    public int tiny;
}

class C
{
    public static Func<Cheap> longLived;
    public static void M()
    { 
        Expensive expensiveLocal = new Expensive();
        Cheap cheapLocal = new Cheap();
        Func<Expensive> shortLived = ()=>expensiveLocal ;
        C.longLived = ()=>cheapLocal;
    }
}

本地变量expensiveLocal的生命周期是多少?本地变量的生命周期通常为 short ;通常局部变量不会超过方法激活。但是,在一个闭包中的会将局部变量的生命周期任意延长到闭包的生命周期。在这种特殊情况下,两个lambdas 共享一个闭包,并且意味着局部变量expensiveLocal的生命周期至少与局部变量cheapLocal的生命周期一样长,因为对闭包的引用刚刚被存储在一个永远存在的静态字段。那个大字节数组可能从不被回收,尽管很久以前只收集了它所引用它的东西;闭包是一个隐藏的参考。

许多语言都有这个问题; C#,VB,JScript等都有词法闭包,这些闭包没有按生命周期分组到变量组。我们正在考虑改变C#和VB,以便对闭包进行更好的生命周期管理,但这是现在的远期工作,所以不能保证。

答案 1 :(得分:4)

没有。没有必要将引用设置为null。

Dispose()用于清理未受管理的资源。 Action<string>是一个manged资源,当Class1的实例超出DoSomething()末尾的范围时,CLR将正确处理。

答案 2 :(得分:0)

不,你没有。垃圾收集器会处理它。

答案 3 :(得分:0)

一旦 DoSomething 返回, myCLass1 就是垃圾收集的候选者。当一个类被垃圾收集时,如果没有未完成的引用,也会收集它的所有成员。所以你不需要做你正在做的事情