C#异步TCP和它的闭包引用实例的垃圾收集?

时间:2011-03-07 16:56:26

标签: c# asynchronous garbage-collection scope

只是想知道异步TCP或其他EAP模式,如果成功处理程序的引用为this,例如理论上,this.state存在对当前实例的引用,因为this通过闭包性质保存在某个生成的对象范围中。因此,即使创建实例的范围已完成执行,实例本身也不应被垃圾收集?

我的代码类似于以下内容:

 public class ATcpClient
    {
        private ATcpState state = null;

        private void Receive()
        {
            // create the callback here, in order to use in dynamic
            AsyncCallback ReceiveCallback = delegate(IAsyncResult ar)
                {
                    try
                    {
                        // Read data from the remote device.
                        this.state.BytesReceived = this.state.Socket.EndReceive(ar);

                    }
                    catch (Exception e)
                    {
                        // ...

                    }
                };

            try
            {
                    this.state.Socket.BeginReceive(this.state.Buffer, 0, this.state.BufferSize, 0,
                        ReceiveCallback, null);
            }
            catch (Exception e)
            {
                // ...
                // ...
            }
        }
}

执行它的代码可能如下所示:

public void DoExecuteCode()
{
    new ATcpClient().Receive();
}

实例是GC会导致Receive()整体失败吗?

1 个答案:

答案 0 :(得分:2)

这取决于编译器的聪明程度。

在你的情况下,是的,this肯定会由代表保持活着,只要代表生活。

让我们看看一个肯定不会让this保持活着的案例:

    private void Receive()
    {
        ATcpState state = this.state;
        // create the callback here, in order to use in dynamic
        AsyncCallback ReceiveCallback = delegate(IAsyncResult ar)
            {
                try
                {
                    // Read data from the remote device.
                    state.BytesReceived = state.Socket.EndReceive(ar);

                }
                catch (Exception e)
                {
                    // ...

                }
            };

        try
        {
                state.Socket.BeginReceive(state.Buffer, 0, state.BufferSize, 0,
                    ReceiveCallback, null);
        }
        catch (Exception e)
        {
            // ...
            // ...
        }
    }

然后是编译器优化可能影响集合行为的情况:

    private readonly ATcpState state = new ATcpState();
    private void Receive()
    {
        // create the callback here, in order to use in dynamic
        AsyncCallback ReceiveCallback = delegate(IAsyncResult ar)
            {
                try
                {
                    // Read data from the remote device.
                    state.BytesReceived = state.Socket.EndReceive(ar);

                }
                catch (Exception e)
                {
                    // ...

                }
            };

        try
        {
                state.Socket.BeginReceive(state.Buffer, 0, state.BufferSize, 0,
                    ReceiveCallback, null);
        }
        catch (Exception e)
        {
            // ...
            // ...
        }
    }

唯一剩下的问题是,该代表的生命周期是多少?挂起操作是否为root,或者我们只是在委托之间有一个循环引用,可能是thisstatestate.Socket和操作?如果这些都不能从根目录中获得,则可以最终确定整个群集(这将关闭套接字,取消操作)。

At least for some objects using the BeginReceive/EndReceive pattern, the operation is NOT a root

对于您的案例(Socket.BeginReceive),在System.Net.Sockets.BaseOverlappedAsyncResult.PinUnmanagedObjects内创建了一个根。