Ras*_*ber 12 .net c# garbage-collection asynchronous webclient
我在一段生产代码中使用以下方法:
private void DownloadData(Uri uri)
{
WebClient webClient = new WebClient();
DownloadDataCompletedEventHandler eh = null;
eh = delegate(object sender, DownloadDataCompletedEventArgs e)
{
webClient.DownloadDataCompleted -= eh;
((IDisposable) webClient).Dispose();
OnDataDownloaded();
};
webClient.DownloadDataCompleted += eh;
webClient.DownloadDataAsync(uri);
}
Run Code Online (Sandbox Code Playgroud)
我现在担心WebClient
在DownloadDataCompleted
调用事件之前实例被垃圾收集可能导致难以重现的错误:退出我的DownloadData()
方法后,没有明显的WebClient
对象引用,因此可能会发生这种情况.
所以我的问题是:这真的可以实现吗?我无法重现该问题,因此可能会发生一些内部事情阻止WebClient
对象被垃圾收集(例如,对象可能在等待响应时在某处注册自己的全局对象).
代码在.NET 2.0上运行,如果这有任何区别.
Jus*_*ant 12
不,在回调完成之前,您的对象不会被GC编辑.根据垃圾收集器是否在.NET中的异步调用期间销毁暂时未引用的对象?," 异步API保留对您的请求的引用(在提交异步IO操作的线程池中),因此在完成之前不会对其进行垃圾回收. "
但是,您的代码也在做它不需要的东西:您不需要分离事件处理程序,也不需要在webclient上调用Dispose.(Dispose()实际上并未由WebClient实现 - 您可以在http://referencesource.microsoft.com/netframework.aspx上的.NET Framework参考源中看到这一点.
因此,您实际上不需要在回调中引用webclient实例.换句话说,以下代码也可以正常工作,并避免从委托内部引用外部局部变量的任何潜在问题(如上所述).
private void DownloadData(Uri uri)
{
WebClient webClient = new WebClient();
DownloadDataCompletedEventHandler eh = null;
eh = delegate(object sender, DownloadDataCompletedEventArgs e)
{
OnDataDownloaded();
};
webClient.DownloadDataCompleted += eh;
webClient.DownloadDataAsync(uri);
}
Run Code Online (Sandbox Code Playgroud)
无论如何,你可能想在别处寻找你的bug来源.我看到的一个地方是HTTP调用的结果 - 你可能正在耗尽内存,可能会遇到服务器错误等.你可以查看e.Error来查看调用是否真的有效.
WebClient
在异步操作正在进行时,我不确定通常是否可以进行垃圾收集,因为可能存在内部引用 - 但更大的问题是:它是否重要?
只要有足够的WebClient
"活着"来维护请求并调用你的处理程序,主要WebClient
对象本身是否被垃圾收集是否重要?
该WebClient
文件没有提到任何关于必须守住的引用(不同于System.Threading.Timer
文档,例如),所以我认为这是合理的假设,这是好的.
在这种特殊情况下,您的委托具有对该委托的引用WebClient
,因此只要委托本身被引用,WebClient
就不能.我的猜测是,系统的某些部分地方需要持有一个回调知道该怎么办时,网络流量到达,并且该回调将最终(间接)导致您的代理,所以你没事.