意外的OutOfMemoryException

时间:2012-10-24 18:13:18

标签: c# memory-management memory-leaks garbage-collection

我曾经有过:

using (MyWebClient client = new MyWebClient(TimeoutInSeconds))
{
   var res = client.DownloadData(par.Base_url);
   //code that checks res
}

现在我有:

using (MyWebClient client = new MyWebClient(TimeoutInSeconds))
{
   client.DownloadDataAsync(new Uri(par.Base_url));
   client.DownloadDataCompleted += (sender, e) =>
   {
       //code that checks e.Result
   }
}    

MyWebClient派生自WebClient。 现在我有很多线程在做这个,在第一种情况下,内存消耗不是问题,而在第二种情况下,我看到内存稳定上升,直到我得到OutOfMemoryException。 我描述了似乎WebClient是罪魁祸首,没有被处理和下载数据被保留。但为什么?两种情况有什么区别?也许e.Result需要以某种方式处理?

2 个答案:

答案 0 :(得分:2)

您的第一个案例将并发下载的数量限制为线程数。您的第二种情况对并发下载的数量没有限制。

答案 1 :(得分:0)

您正在第二个选项中立即处理WebClient。你有几个选择:

  1. 如果您使用的是.NET 4.5(或安装了Visual Studio 2012的.NET 4.0和安装了AsyncTargetingPack),您可以执行var res = await client.DownloadDataAsync(par.Base_url);并且代码看起来与您的第一行类似但实际上是异步的。
  2. 使用正常延续并摆脱using阻止
  3. 第一个选项如下:

    using (MyWebClient client = new MyWebClient(TimeoutInSeconds))
    {
       var res = await client.DownloadDataAsync(par.Base_url);
       //code that checks res
    }
    

    第二个选项如下:

    var client = new MyWebClient(TimeoutInSeconds);
    
    client.DownloadDataAsync(new Uri(par.Base_url))
        .ContinueWith(t =>
        {
            client.Dispose();
    
            var res = t.Result;
    
            //code that checks res
        }
    }  
    

    HOWEVER

    您必须根据您使用的解决方案更改线程方法。代码的第一个版本是同步运行的,所以如果你有一个专用于URL的线程(或连接,或者你要将它们拆分),下载将在该线程上同步运行并阻止它。但是,如果您选择其中任何一个选项,您将最终使用IO完成线程来完成您的工作,将其从主线程中分离出来。从长远来看,这可能是更好,但这意味着您必须注意并行提交这些请求的数量。