只是想知道在异步 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();
}
实例会不会是导致 Receive() 整体失败的 GC?
最佳答案
这取决于编译器的聪明程度。
在您的情况下,是的,this
肯定会由委托(delegate)人保持事件状态,只要委托(delegate)人还活着。
让我们看一个绝对不会让 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)
{
// ...
// ...
}
}
剩下的唯一问题是,该代表的生命周期是多少?挂起的操作是一个根,还是我们只是在委托(delegate)之间有一个循环引用,可能是 this
、state
、state.Socket
和手术?如果这些都不能从根访问,那么可以完成整个束(这将关闭套接字,取消操作)。
At least for some objects using the BeginReceive
/EndReceive
pattern, the operation is NOT a root
对于您的案例 (Socket.BeginReceive
),它看起来像是在 System.Net.Sockets.BaseOverlappedAsyncResult.PinUnmanagedObjects
中创建了一个根。
关于C# 异步 TCP 及其闭包引用实例的垃圾回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5222575/