ImageList / 画像 OutOfMemoryException
-
22-08-2019 - |
質問
ImageList から画像を取得するときに 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 自体の再描画が遅くなり、再描画中に画面上にアーティファクトが表示されることです。
他にこれを経験した人はいますか?それとも回避策を知っていますか?
解決
処分していますか graphics
?また、あなたが述べたように画像を破棄する場合は、それが ImageList から削除されていることを確認する必要があります。そうしないと、さらに問題が発生します。画像の形式は何ですか?
一般に、画像が関係するときにメモリ不足の問題が発生する場合、問題は、一部のメソッドが一部の画像形式を好まないか、または 9/10 の場合、グラフィック オブジェクトの 1 つのライフサイクルを誤解しているかのどちらかです。
- すべてをチェックしてください
Graphics
使用してそれらを入れますusing
ブロック。 - あなたの
Image
ライフサイクルに注意し、コピー、破棄、基になるストリームの終了などに注意してください。 - メモリ マネージャー (VS2008 にはメモリ マネージャーが組み込まれています) をロードし、何がうまくクリーンアップされていないのかを確認します。
編集:
これが私が見つけることができる最良のオプションです、使用してください ImageList.Draw(graphics, x, y, width, height, index)
. 。これにより、イメージのコピーを作成する代わりに内部ハンドルが使用されます。
他のヒント
私は自分のアプリケーションでこの問題を解決するために管理している。
ジェイソンはあなたがブロック、またはそれに相当する「を使用して」使用を確認する必要があり、答えを持っています。
私はVBを使用して、同等の私はBitMap.Disposeを呼び出し、「最後に」の部分でビットマップ=何も設定していない、新しいビットマップを作成した。最後たび...キャッチ...してみ使用することでした。
これは、私が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