2011-09-15 27 views
2

画像データベースとスライドショーの2つのWindowsフォームプログラムがあります。Visual Studio 2010でメモリ不足の問題が発生するVisual Basic .Net 4.0

スライドショーを連続画像の各新しいスイッチと共に使用

メモリをインクリメントすることなく、表示ピクチャを更新します。しかし、私は

には、データベースに追加する画像のサムネイルを表示するための50個のピクチャボックスがあります。サイズ(57,40)の各ピクチャボックスが小さいサイズのサムネイル(< 12K)で更新されると、IDEによって使用されるメモリは、サムネイルのピクチャボックスがロードされる前に32ビットXPシステムで約1GBから660MB 。

サイズ(57,40)の約30枚のピクチャボックスが.jpgソースファイル> 3MBからロードされると、IDEメモリの使用量は約2.1GBに増加します。 (問題は.jpg画像では簡単に遭遇しません。< = 15K、すべてのサムネイルは< 1.3GB memを使用して使用できます)。

問題は、平均.jpgファイルサイズ> 3MBのHDキャノンカメラの画像で表示されます.jpg画像は表示されたサムネイルの30個のピクチャボックスにロードされ、表示された画像をクリックして起動し、 2.3GBのメモリ使用量を超えると、メモリ不足によるクラッシュが発生します。

これはVB2010または.NET 4.0のバグですか?

すべての画像がサムネイルとして表示されたら、すべてのサムネイルを含むパネル上の50個のピクチャボックスのいずれかをマウスでクリックすると、フォーム上に1つ大きな画像ボックスが更新され、 1024,768)。任意のサムネイルをクリックすると、1つの大きなピクチャボックスに関連するピクチャがファイルから表示されますが、同時にシステムメモリはクリックイベントあたり約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は断片化を減らそうとしますが、混雑した部屋で巨大なデスクを動かすようなこともあり、奇跡は起こりません。

3)配列は動的には拡張されないため、内部的にコレクションはスペースを使い果たすたびに新しい配列を配置する必要があります。通常、毎回配列のサイズが倍になります。これは、ほとんどのコレクションの ".Capacity"プロパティです。コレクションの.Capacityと.Lengthを監視するには、いくつかのデバッグを使用する必要があります。コレクションがそのサイズに達するたびに、それを2倍に観察します。私。 128,256など

倍になると、新しい配列を割り当ててから、古い配列の内容をコピーしてから、古い配列を割り当て解除する必要があります。したがって、256(または64のような他の2の累乗)のコレクションを持っていて、もう1つのアイテムを追加した場合、内部的にコレクションは新しい512項目の配列を割り当て、前の配列からコピーします。この移行プロセス中に、512および256の両方のメモリアレイがあります。だからあなたは257アイテムのスペースが必要ですが、257アイテムを追加するには3倍のスペースが必要です(256 + 512 = 768)。

スタックトレースを使用して、ピクチャをコレクションに追加しようとしているときに例外が発生しているかどうかを判断することができます。コールが追加されているため、必要に応じてコレクションが展開されます。また、通話が2の累乗になる直前に長さが表示されます。

画像が512MBあり、コレクションを1つ増やす必要がある場合、.NETは1GBの配列を割り当てるためのスペースを見つけなければなりません画像のしたがって、その容量を拡大しなければならないコレクションの移行中には、1.5ギガビットのラムが必要になります。 .NETがフラグメンテーションを最小限に抑えるために必要なすべてのステップであっても、フラグメンテーションによる1GBのRAMの連続ブロックを検出するのは非常に難しいでしょう。 (誰かが、おそらく参照の配列がはるかに小さいことを指摘しますが、あなたが扱っているものを言うのは難しいです。)

ソリューション: あなたはこれがあなたの問題の原因、そして解決策である判断した場合必要なアイテムの数を予測し、アレイの容量を事前に設定することです。だから、あなたが画像のリストを持っているなら、最初にそれらの画像の数を取得し、コレクションの容量をその量に設定し、おそらく10%増やすことをお勧めします。このようにして300アイテムあれば、容量を350に設定することができます。その代わりに、小さなヘッドルームで事前に容量を見積もってから、拡張する必要はないため、3倍のスパイクを経験しません拡張のためのメモリ使用量。

Google .NETメモリプロファイラー多くのプロファイラーがあり、また、デバッグにも勝つので、メモリの割り当てと解放、断片化の詳細を見ることができます。

+0

コード内に問題が見つかりました。 – VMAtm

2

@AaronLSは、究極の睾丸反応を示したので、読んで覚えておいてください。
あなたのコードでメモリリークがここにある:あなたがImage.FromFileメソッドを使用するよう

PBx1.Image = Nothing 
PBx1.Visible = False 

PBx1.Imageは、Image型オブジェクトです。 ImageIDisposableです。つまり、アンマネージコードでネイティブリソースを使用しています。

あなたは明示的にこのコードでは、PBX1のため.Dispose()メソッドを呼び出す必要があります:

'PBx1.Image = Nothing 
If PBx1.Image IsNot Nothing Then PBx1.Image.Dispose() End If 
PBx1.Visible = False 
関連する問題