什么阻止物体被处置? /异步流程是否保持对象存活?

时间:2013-05-30 08:44:44

标签: c# asynchronous garbage-collection

请考虑以下代码:

public class ChainHandler
{
    public void ProcessTopUp(string amount, string phone, ResponseCallback responseCallback)
    {
        var statebag = GetStateBag();

        ICommand basecommand = new BlmLoginCommand(statebag);
        basecommand .SetNext(new BlmDynamicCommand(statebag, RequestMessageEvent.TCD_RecargaTAE10, new Dictionary<string, string> { { "amt", amount }, { "cel", phone } }))
               .SetNext(new BlmDynamicCommand(statebag, RequestMessageEvent.TCD_BuyProduct))
               .SetNext(new BlmEndCommand(statebag, responseCallback));

        basecommand.ExecuteAsync();
    }


}

class Program
{
    static void Main(string[] args)
    {
        ChainHandler ch = new ChainHandler();

        ch.ProcessTopUp("5.00", "0123456789", OnProcessResponse);

        Console.ReadLine();
    }

    private static void OnProcessResponse()
    {
        //...
    }
}

方法“ExecuteAsync”启动使用命令的异步流程。 这些命令在内部使用Socket类异步(基于事件的异步模式)。

问题是:是否有可能永远不会到达EndCommand,因为在离开“ExecuteAsync”方法后对象basecommand被释放了?

甚至.net知道EndCommand有一个回调方法吗?

或者.net是否足够智能以保持对象存活直到异步流完成?

如果对象不活动,我该怎么做才能指示垃圾收集器不要处理basecommand?

2 个答案:

答案 0 :(得分:3)

准确性在这里很重要。对象不会自动处理。它总是在代码中显式完成,可以通过 using 语句或调用Dispose()方法完成。因此,如果您不在代码中处置,那么从来没有问题。

你可能想说的是&#34;垃圾收集&#34;。这在.NET中是非常简单的,只要垃圾收集器可以看到对象的引用,并且该引用由另一个本身存活的对象持有,那么就不会收集对象。

然而,并不总是很清楚存储该引用的位置。 C#编译器可以重写您的代码并将其从类中的方法移动到隐藏类的方法。隐藏的类具有不可言喻的名称,并且具有存储引用的字段。垃圾收集器可以看到哪个,从而防止收集对象。将代码中的引用复制到该隐藏类对象的字段中的技术术语是"variable capturing"

此代码重写技巧在C#中的许多地方使用。最初用语言实现,以支持匿名方法和迭代器。并在以后的版本中进行扩展,以实现lambda表达式和异步方法。查看正在发生的事情的好方法是查看C#编译器生成的代码。使用ildasm.exe或不完美的反编译器可见。否则这肯定适合足够聪明的&#34;绰号。

答案 1 :(得分:1)

在您的情况下,您的命令将不会被处置,因为它具有委托/回调引用。这意味着,只要代理人活着,命令对象将由代理保持活动状态。最后,一旦执行了回调,GC就会选择不接触(没有root的对象)。

更新:

其他情况是,如果没有回调参考,该怎么办。

在这种情况下,您的对象不会立即进行垃圾回收,因为EPM(您在代码中遵循的模式)API会在线程池中保留对您的请求的引用,特别是IO完成线程。这提示GC在完成之前不要触摸或收集。