2009-05-19 60 views
4

從一個ImageList獲取圖像時,我患有OutOfMemoryException我一直無法找到問題的合適解決方案。ImageList/Image OutOfMemoryException

我有一個自定義ListView控件,它附加了一個用於繪製ListViewItems的事件。然後調用一個靜態方法來設計該項目。

對於大約300個項目的ListView,每次滾動ListView時,我們都會讓內存跳到100Mb左右。有問題的代碼已經被追查到以下幾點:

Image image = item.ImageList.Images[item.ImageKey]; 
if (image != null) 
{ 
    Size imageOffset = new Size((bounds.Width - image.Width)/2, 2); 
    Point imagePosition = bounds.Location + imageOffset; 
    graphics.DrawImageUnscaled(image, imagePosition); 
} 

看來(當然在WinXP)表示,垃圾收集工作不正常,導致內存盤旋。我們嘗試添加一個image.Dispose()直接在代碼塊之後來解決問題,但這沒有任何作用。

到目前爲止我設法找到的唯一解決方案是在調用GC.Collect()的靜態方法的末尾。然而,這個問題是,它會導致ListView緩慢地重新繪製自己,並且當它試圖重新繪製時,最終會在屏幕上出現工件。

有沒有其他人經歷過這個?或者知道解決方法?

+0

我已經經歷了兩個不同的應用程序,他們都不涉及圖像或ListView outofmemoryexceptions。不幸的是,我能夠找到的唯一解決方案是經常調用GC.Collect()。 – Crispy 2009-05-19 13:36:07

回答

4

您正在處置graphics?此外,它像你提到的那樣處理你的圖像,然後你需要確保它被從ImageList中取出,否則會引發更多問題。圖像的格式是什麼?

一般而言,當涉及圖像時出現內存不足問題時,您的問題將是某種方法不喜歡某種圖像格式,或者9/10次,您誤解了其中一個圖形對象的生命週期。

  • 檢查所有的Graphics的用法,並把它們放在using塊。
  • 檢查Image生命週期,並小心將其複製,處置他們,收盤底層流等
  • 加載了一個內存管理器(VS2008有一個內置),看看有什麼是沒有得到清理很好。

編輯:

這是我能找到,使用ImageList.Draw (graphics, x, y, width, height, index)的最佳選擇。這將使用內部手柄,而不是創建圖像的副本。

+0

感謝您的回覆。這是關於圖像配置的一個好處,我可能需要刪除該行,然後離開垃圾收集。 我不想放棄圖形對象,因爲我從EventArgs中抓取它,因此我不知道它是否會在其他地方使用。 圖像各不相同,我們發現它的時間是一個圖標文件,所以我們使用Icon.ToBitmap()。 將試圖追查內存管理器,這聽起來非常有用。 – Ian 2009-05-20 08:05:59

0

我已經成功解決了我的應用程序中的這個問題。

傑森有答案,你必須確保你使用「使用」塊,或他們的等價物。

我使用VB,等價的是使用Try ... Catch ...最後,每當我創建一個新的位圖,調用BitMap.Dispose並在「Finally」部分中設置Bitmap = Nothing。

這似乎是一個非常普遍的問題,從我花在Google上的這段時間來看。下面的代碼還允許任何圖像在縮小到縮略圖時保留其縱橫比,這對Google來說似乎很難實現!

代碼:

Private Function AspectedImage(ByVal ImagePath As String, ByVal SizeWanted As Integer) As Image 

    Dim myBitmap, WhiteSpace As System.Drawing.Bitmap 
    Dim myGraphics As Graphics 
    Dim myDestination As Rectangle 
    Dim MaxDimension As Integer 
    Dim ReductionRatio As Double 

    Try 

     'create an instance of bitmap based on a file 
     myBitmap = New System.Drawing.Bitmap(ImagePath) 



     'create a new square blank bitmap the right size 
     If myBitmap.Height >= myBitmap.Width Then MaxDimension = myBitmap.Height Else MaxDimension = myBitmap.Width 
     ReductionRatio = SizeWanted/MaxDimension 
     WhiteSpace = New System.Drawing.Bitmap(SizeWanted, SizeWanted) 

     'get the drawing surface of the new blank bitmap 
     myGraphics = Graphics.FromImage(WhiteSpace) 

     'find out if the photo is landscape or portrait 
     Dim WhiteGap As Double 

     If myBitmap.Height > myBitmap.Width Then 'portrait 
      WhiteGap = ((myBitmap.Width - myBitmap.Height)/2) * -1 
      myDestination = New Rectangle(x:=CInt(WhiteGap * ReductionRatio), y:=0, Width:=Int(myBitmap.Width * ReductionRatio), Height:=Int(myBitmap.Height * ReductionRatio)) 
     Else 'landscape 
      WhiteGap = ((myBitmap.Width - myBitmap.Height)/2) 
      'create a destination rectangle 
      myDestination = New Rectangle(x:=0, y:=CInt(WhiteGap * ReductionRatio), Width:=Int(myBitmap.Width * ReductionRatio), Height:=Int(myBitmap.Height * ReductionRatio)) 
     End If 

     'draw the image on the white square 
     myGraphics.DrawImage(image:=myBitmap, rect:=myDestination) 
     AspectedImage = WhiteSpace 

    Catch ex As Exception 
     myBitmap = New System.Drawing.Bitmap("") 
     AspectedImage = New System.Drawing.Bitmap(4, 4) 
     ImageBufferExceeded = True 
     MsgBox("Image Buffer exceeded, too many images in memory. If the one(s) you want can't be seen, please restart the application and navigate straight to your images") 
    Finally 
     myBitmap.Dispose() 
     myBitmap = Nothing 
     WhiteSpace = Nothing 
    End Try 

End Function