繁体   English   中英

ConcurrentQueue操作给出OutofMemory错误。

[英]ConcurrentQueue Operation is giving OutofMemory Error.

我了解这个问题可能太笼统了。 但是我尝试了很多事情,但我不知道该如何解决。

我正在使用ConcurrentQueue进行多线程操作。 一个线程正在从服务器下载图像并将其保存到队列。 这是该代码:

 public static void DownloadImage()
    {
        string baseUrl = "http://someurl";
        //int numIterations = 5;

        HttpWebRequest request = null;
        foreach (var fileName in fileNames)
        {
                string url = string.Format(baseUrl, fileName);
                request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "GET";
                request.ContentType = "application/x-www-form-urlencoded";
                var response = (HttpWebResponse)request.GetResponse();
                Stream stream = response.GetResponseStream();
                img = Image.FromStream(stream);
                ImageFileName FileNameImage = new ImageFileName(fileName, img);
                ImageQueue.Enqueue(FileNameImage);
                Console.WriteLine("Count after Enqueue: {0}", ImageQueue.Count);

         }

另一个线程从队列中获取图像并将其保存在目标文件夹中。 这是该代码:

public static void SaveImage()
    {
        while (true)
        {
            if (!ImageQueue.IsEmpty)
            {
                foreach (var newobject2 in ImageQueue)
                {

                    Image img2 = newobject2.Image;
                    img2.Save("C:\\path" + newobject2.ImageName);
                    ZoomThumbnail = img2;
                    ZoomSmall = img2;
                    ZoomLarge = img2;

                    ZoomThumbnail = GenerateThumbnail(ZoomThumbnail, 86, false);
                    ZoomSmall = GenerateThumbnail(ZoomSmall, 400, false);
                    ZoomLarge = GenerateThumbnail(ZoomLarge, 1200, false);

                    ZoomThumbnail.Save("C:\\path" + newobject2.ImageName + "_Thumb.jpg");
                    ZoomSmall.Save("C:\\path" + newobject2.ImageName + "_ZoomSmall.jpg");
                    ZoomLarge.Save("C:\\path" + newobject2.ImageName + "_ZoomLarge.jpg");
                    ImageFileName imgobject3 = new ImageFileName();
                    ImageQueue.TryDequeue(out imgobject3);
                    Console.WriteLine("Count after Deque: {0}", ImageQueue.Count);

                }


            }


        }

    }

我从Button_Click()调用这两个线程,如下所示:

Thread DownloadThread = new Thread(DownloadImage);
  DownloadThread.Start();
  Thread SaveThread = new Thread(SaveImage);
  SaveThread.Start();

每当队列数达到68时,我都会收到MemoryFull错误。我不确定如何避免这种情况。 我尝试使用Thread.Sleep来避免这种情况。 例如,我尝试了: foreach循环后的Thread.Sleep(500) 每当我在foreach尝试它时,在任何给定点ImageQueue.Count = 1它都可以正常工作。 我哪里出错了?

您实际上从未从队列中删除图像。 您遍历它们,但从未使它们出队。 您还有一个问题,当枚举队列时,只要队列中当前没有更多项目,可枚举将停止。 您不想这样做,可能还没有完成。

您要做的是使用BlockingCollection而不是ConcurrentQueue ,这样,如果当前没有更多的项目,您可以等待而不是停止。 完成此操作后,可以使用foreach(var item in queue.GetConsumingEnumerable()) 这将进行所有需要的更改。 它会在您迭代时从队列中删除项目,如果当前没有项目,它会等待更多项目。

正如Guffa的答案所述,除了进行此更改外,您还需要处理图像对象。 完成图像处理后,可以将它们放在循环主体的末尾。

您正在创建许多不处理的Image对象。 您应该在创建的每个缩略图上调用“ Dispose ”。

而且,您要出队的对象包含一个Image对象,当不再需要它时,应该将其处置。


旁注:您不应该枚举队列中的项目并在循环内将项目取名。 而是在循环本身中使用TryDequeue方法:

ImageFileName imgobject2;
while (ImageQueue.TryDequeue(out imgobject2)) {
  ...
}

另一个注意事项:当队列为空时,您的代码将进入一个紧密循环,这需要大量的CPU功能来非常快速地重复进行相同的检查。 您应该使用一种机制来挂起线程,直到队列发生故障,或者至少休眠一会儿再重新检查队列。

在处理完图像之后,应该在ZoomLarge语句之后进行处理,因为在此之后,您将不再使用它。 使用Generate语句可以创建新图像。

1,似乎您正在引用所有图像以将其保留在内存中,而不允许垃圾收集器收集它们。

另外,在完成使用对象之后,可以像下面这样显式地处置它们:

Image img2 = newobject2.Image;
img2.Dispose();

2.您正在做的是每次在while循环中都枚举所有图像,我不确定这是您想要的。 您应该做的是尝试使项目出队:

FileImageName myImage;
ImageQueue.TryDequeue(out myImage);

if (myImage != null)
{
// Do work on the image
}

您可能要看一下BlockingCollection类( 在此 ),我已经成功地将其用于这种“生产者-消费者”模式。

某人(生产者)将项目放入集合中,一个或多个“消费者” b / g线程将下一个可用项目从集合中移出并对其进行处理。 您还可以配置要使用的使用者线程数(例如,用于多核PC)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM