2011-09-15 108 views
2

我有兩個Windows窗體程序,它是一個圖片數據庫和幻燈片放映。所述Visual Studio 2010中的內存不足問題Visual Basic .NET 4.0

幻燈片連續地更新所顯示的圖片框,而不遞增與畫面的每個新的交換機中使用的

存儲器。但是,我有第二種形式,

有50個圖片框,旨在顯示要添加到數據庫的圖片的縮略圖。由於每個尺寸爲(57,40)的圖片盒都使用小尺寸縮略圖(< 12K)進行更新,因此在32位XP系統上IDE使用的內存略高於1GB,從加載任何縮略圖圖片盒之前的約660MB 。

從.jpg源文件加載大約30個大小(57,40)的pictureboxes到大於3MB,IDE內存使用量增加到大約2.1GB。 (問題不容易遇到.jpg圖像< = 15K和所有50個縮略圖可與<使用1.3 GB內存使用)。

問題顯示自身的平均.jpg文件大小大於3MB的圖像每個高清佳能相機.jpg圖像被加載到30個顯示的縮略圖pictureboxes,我開始點擊左右選擇顯示的圖片和使用內存快速上升,超過2.3GB的內存使用率導致內存不足崩潰。

這是VB2010或.NET 4.0中的錯誤嗎?

將所有圖片以縮略圖形式顯示後,鼠標單擊包含所有縮略圖的面板上的50個圖片框中的任意一個,即可更新圖片上的單個大型圖片箱,以在單個圖片框中顯示圖片, 1024,768)。當單擊任何縮略圖時,單個大圖片框會顯示來自文件的相關圖片,但與此同時,系統內存每增加約240KB的點擊事件。最終,在大約2.3GB的系統內存使用情況下,程序崩潰並出現內存不足錯誤。

我怎樣才能得到程序時

它與只是另一張照片更新到恢復由相同圖片框使用的內存?

部分代碼如下:

' Each Thumbnail has a click event 
'PB49 is a PictureBox max size (57,40) used as a thumbnail display, all 50 are on a panel 
Private Sub PB49_Click(sender As System.Object, e As System.EventArgs) Handles PB49.Click 
    'PB(50) is an Integer Array flagging Pictures to add 
    If PB(49) = 1 Then PB(49) = 0 Else PB(49) = 1 
    If PB(49) = 1 Then 
     CheckBox49.Checked = True  'Tiny Checkbox on thumbnail 
     F$ = ListAddFiles.Items(48)  'ListFileBox of FileNames 
     PBx1.Image = Image.FromFile(F$) 'Gets filename and path and loads image into PictureBox 
     PBx1.Visible = True 'Large PictureBox (1024,768)shows Pic F$ located on Form 
    Else 
     CheckBox49.Checked = False 
     PBx1.Image = Nothing 
     PBx1.Visible = False 
    End If 
End Sub 

我使用上安裝XP PRO 32-Bit SP3 4GB RAMVisual Studio Ultimate SP1 updated .NET 4.0

+0

你處置了需要配置的對象? –

+0

你不應該在你的問題中使用這麼多'?'。 – VMAtm

+0

這絕對是你的錯誤,而不是VS. – VMAtm

回答

2

當您隱藏圖像時,是否有可能再次加載圖像。即你將它隱藏起來,而隱藏的那個會留在那裏,並在稍後再次添加。因此,你正在積累大量的隱藏圖像?

.NET應用程序中的「內存泄漏」通常是由於沒有清除引用或從所有集合中刪除對象而導致的結果。只要某個對象具有某個地方的引用,無論是某個表單的控件集合中的某個控件還是您自己的集合中的某個控件,它都將保留在內存中。我不確定你的邏輯是用於顯示/隱藏圖片,但也許你需要刪除圖片,並確保你清除所有相關控件的引用。控制集合可以嵌套的方式,很容易錯過一個地方。圖像相關的控件可能會帶來很多額外的開銷,所以如果你有很多未使用的控件隱藏在內存中,那麼這可能是一個問題。

你說你有50個圖片框,但是你有更多的圖片比集合中沒有顯示的圖片。如果你已經將它們加載到一個集合中,那麼無論它們是否被顯示,它們都可能佔用內存。

夫婦的事情要注意。

1)32位Windows中的進程最多可用2GB內存。有一些方法可以在一臺機器上將其配置爲3GB,但通常不應該指望擁有超過2GB的可用空間。 Ojn最重要的是,通常的內存碎片可能會導致您出現OutOfMemory異常,即使看起來您擁有大量可用內存。

2)當你處理.NET集合時,通常在內部它們被實現爲數組。數組是連續的內存塊。因此,即使有足夠的可用內存,也可能會發生OutOfMemory異常,因爲沒有足夠的連續內存塊(由於碎片)。 .NET試圖減少fragementation,但有時候就像在一個擁擠的房間裏移動一個巨大的桌子一樣,它不能創造奇蹟。 3)由於數組不會動態擴展,因此集合內部必須在空間不足時分配新數組。通常每次都會使數組大小加倍。這是大多數收藏的「.Capacity」屬性。您應該使用一些調試來監視集合的.Capacity和.Length。每當收藏達到這個尺寸時,您都會觀察它。即128,256等

每當它加倍時,它必須分配一個新數組,然後在釋放舊數組之前複製舊數組的內容。因此,如果你有一個擁有256個(或者其他權力爲2個像64個)項目的集合,然後再添加一個項目,那麼集合在內部分配一個新的512項目數組,然後從前一個數組複製到它。在這個過渡過程中,你在內存中都有一個512和256的數組。所以雖然你只需要257個物品的空間,但添加第257個物品需要三倍的空間(256 + 512 = 768)。

您可以使用堆棧跟蹤來確定在嘗試向收集中添加圖片時是否發生異常,因爲它在調用中添加了時間,該時間是收集如果需要時展開的地方。你還會注意到在調用之前的長度將是2的冪。

所以如果你有512MB的圖像並且集合需要擴展以增加一個,.NET必須找到空間來分配一個1GB的數組的圖像。所以在這個系列的擴展過程中,它需要1.5G的RAM。對於.NET而言,由於碎片,找到一個1gb的ram連續塊是非常困難的,即使所有的步驟.NET儘量減少碎片,但仍然有很多控制。 (有人可能會指出,引用數組要小得多,但很難說什麼你正在處理。)

解決方案: 如果你確定這是你的問題的原因,然後解決方案預測您將需要多少物品,並預先設置陣列的容量。因此,如果您有一張圖像列表,那麼最好首先計算這些圖像的數量,然後將集合的容量設置爲該數量,並且可能再加上10%或更多。這樣,如果您有300件物品,則可以將容量設置爲350.這樣,您可以預先使用一個小頂部空間來預估容量,那麼它將永遠不會擴展,因此不會經歷3倍的峯值內存使用情況進行擴展。

Google .NET內存分析器。有很多配置文件,也贏得調試,可以讓你看到內存分配和重新分配的細節以及碎片。

+0

在代碼中發現問題。 – VMAtm

2

@AaronLS給了一個終極熱情的答案,所以閱讀並記住它。
在你的代碼中的內存泄漏是在這裏:

PBx1.Image = Nothing 
PBx1.Visible = False 

PBx1.Image是Image類型的對象,當您使用Image.FromFile方法。而ImageIDisposable,這意味着它在非託管代碼中使用本地資源。

您必須顯式調用PBX1的.Dispose()方法在此代碼:

'PBx1.Image = Nothing 
If PBx1.Image IsNot Nothing Then PBx1.Image.Dispose() End If 
PBx1.Visible = False