3

我正在使用以下代碼片段將圖像作爲縮略圖加載到FlowLayoutPanel控件中。不幸的是我得到了一個OutOfMemory異常。加載圖像時出現內存不足異常

正如你已經猜到了內存泄漏的行

Pedit.Image = System.Drawing.Image.FromStream(fs) 

所以,我怎麼能優化下面的代碼中發現?

Private Sub LoadImagesCommon(ByVal FlowPanel As FlowLayoutPanel, ByVal fi As FileInfo) 
     Pedit = New DevExpress.XtraEditors.PictureEdit 
     Pedit.Width = txtIconsWidth.EditValue 
     Pedit.Height = Pedit.Width/(4/3) 
     Dim fs As System.IO.FileStream 
     fs = New System.IO.FileStream(fi.FullName, IO.FileMode.Open, IO.FileAccess.Read) 
     Pedit.Image = System.Drawing.Image.FromStream(fs) 
     fs.Close() 
     fs.Dispose() 
     Pedit.Properties.SizeMode = DevExpress.XtraEditors.Controls.PictureSizeMode.Zoom 

     If FlowPanel Is flowR Then 
      AddHandler Pedit.MouseClick, AddressOf Pedit_MouseClick 
      AddHandler Pedit.MouseEnter, AddressOf Pedit_MouseEnter 
      AddHandler Pedit.MouseLeave, AddressOf Pedit_MouseLeave 
     End If 

     FlowPanel.Controls.Add(Pedit) 
    End Sub 

更新:同時加載多個圖像時出現的問題(在300dpi的3264x2448px - 每個圖像約爲3MB的)

+0

您是否嘗試過通過刪除所有多餘的代碼,只嘗試加載圖像隔離問題?你有沒有嘗試將加載的圖像分配給「正常」圖像顯示控件? – 2011-01-31 16:58:01

+1

加載一張圖像或多張圖像後,內存是否耗盡?它只是一個特定的圖像給你帶來麻煩,或者當你嘗試加載任何圖像時會失敗嗎?圖像特別大嗎?請詳細說明我們能做的最好的事情是猜測。 – 2011-01-31 17:05:24

+0

@Jim。你好,請你檢查一下更新嗎? – OrElse 2011-01-31 17:12:49

回答

3

可以在幾個步驟解決這個問題:

  • 獲得從文件依賴性免費的,你必須複製的影像。通過真正把它繪製到一個新的位圖上,你不能複製它。
  • 既然你想縮略圖,你的源位圖是相當大的,結合這縮小圖像。
5

的文檔Image.FromFile(這是關係到你的FromStream)說會如果文件不是有效的圖像格式或者GDI +不支持像素格式,則丟棄OutOfMemoryException。有沒有可能你試圖加載不支持的圖片類型?

此外,文檔Image.FromStream說,你必須保持圖像的生命週期的流打開,所以即使你的代碼加載圖像,你可能會得到一個錯誤,因爲你正在關閉文件,而圖像仍然活躍。請參閱http://msdn.microsoft.com/en-us/library/93z9ee4x.aspx

3

夫婦的想法:

首先,吉姆曾表示,使用Image.FromStream當流應該保持開放的形象的生命週期的MSDN頁面上說。因此,我建議將文件的內容複製到MemoryStream中,並使用後者來創建Image實例。所以你可以儘快釋放文件句柄。其次,你使用的圖像相當大(未壓縮,因爲它們將存在於內存中,寬度×高度×BytesPerPixel)。假設你使用它們的上下文可能允許它們變小,考慮調整它們的大小,並且可能將重新調整後的版本緩存到某個地方供以後使用。

最後,不要忘記在圖像和流不再需要時處理。

0

我有同樣的問題。 Jim Mischel的回答讓我發現加載一個無辜的.txt文件是罪魁禍首。這是我的方法,以防萬一有興趣。

這裏是我的方法:

/// <summary> 
/// Loads every image from the folder specified as param. 
/// </summary> 
/// <param name="pDirectory">Path to the directory from which you want to load images. 
/// NOTE: this method will throws exceptions if the argument causes 
/// <code>Directory.GetFiles(path)</code> to throw an exception.</param> 
/// <returns>An ImageList, if no files are found, it'll be empty (not null).</returns> 
public static ImageList InitImageListFromDirectory(string pDirectory) 
{ 
    ImageList imageList = new ImageList(); 

    foreach (string f in System.IO.Directory.GetFiles(pDirectory)) 
    { 
     try 
     { 
      Image img = Image.FromFile(f); 
      imageList.Images.Add(img); 
     } 
     catch 
     { 
      // Out of Memory Exceptions are thrown in Image.FromFile if you pass in a non-image file. 
     } 
    } 

    return imageList; 
}