Parallel.ForEach(...)中的System.Drawing内存泄漏

时间:2012-06-16 12:21:21

标签: c# memory-leaks task-parallel-library system.drawing

我正在使用System.Drawing类处理图像列表。如果我在正常的foreach循环中处理图像一切都很好,但是当我在图像上循环时(带图像我不是指任何一次性System.Drawing.Image isntances但是图像的源(urls))和Parallel.ForEach我运行内存不足。我的过程变得越来越大(> 1GB)。似乎没有释放Graphic缓冲区,因为我注意释放所有资源。这可以通过切换到非平行foreach(...)来确认。该过程保持在大约60 MB。

你遇到过这样的问题吗?

        // memory "leak". process grows beyound 1GB to infinity
        Parallel.ForEach(urls, url =>
        {
            ImageResizer.DownloadAndResizeImage(url);
        });


        // no memory "leak"
        foreach (string url in urls)
        {
            ImageResizer.DownloadAndResizeImage(url);
        }

2 个答案:

答案 0 :(得分:3)

我希望Parallel.Invoke在处理时消耗更多内存,因为它一次尝试处理多个图像。 Parallel.Invoke还会在它返回之前等待所有任务完成,因为你说出现“Out of Memory”错误,我猜它永远不会返回,所以没有办法知道是否发生了内存泄漏。

尝试使用Parallel.Invoke处理两个图像,并查看进程完成后内存是否返回到已知的起始点。如果是这样,那么没有内存泄漏 - 你只是试图处理超过系统一次可以处理的内容。

如果是这种情况,请尝试使用Parallel.ForEach,而不是使用MaxDegreeOfParallelism限制线程数。

我会尝试的第一件事(如果你有4个核心):

Parallel.ForEach( 
    urls, 
    new ParallelOptions { MaxDegreeOfParallelism = 4 }, 
    url => { ImageResizer.DownloadAndResizeImage(url); } 
); 

编辑:

好吧,问题似乎已经从Parallel.Invoke更改为Parallel.ForEach并添加了一些代码:),但这不应该更改我的答案,因为Parallel.ForEach将等到所有任务都完成。

我猜想DownloadAndResizeImage()方法可能是罪魁祸首,而不是Parallel。为了正确地异步处理请求,使用低级网络API需要大量的开发。使用Microsoft的WebClient或HttpWebRequest对象具有已知的瓶颈,这些瓶颈限制了可以通过多线程异步进行的请求数。我知道这一点,因为我最近尝试了同样的事情,最后自己写了套接字层。开心辞典!

所以可能发生的事情是每个请求都在进行,一次只处理两个请求,而其他请求将在队列中等待轮到他们。但是在等待时,所有对象都被初始化,导致内存增长。最终(如果你有足够的内存),你会开始看到执行时间太长的失败请求会发生一些超时。

有一些免费软件应用程序可用于筛选数百个请求。我建议抓住他们的一些低级代码并在你的应用程序中实现它。这是开始学习套接字的好地方。

http://msdn.microsoft.com/en-us/magazine/cc300760.aspx

答案 1 :(得分:1)

Parallel.ForEach比CPU内核更容易启动更多线程。它可以出现内存泄漏,因为有50个线程或正在运行。

您需要在处理过程中暂停调试器并查看是否有太多线程在运行。