簡體   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