Windows Mobile 6(WF/C#)アプリケーションを開発しようとしています。フォームは1つだけで、フォームにはPictureBoxオブジェクトのみがあります。その上で、すべての必要なコントロールまたは必要なものを何でも描画します。
私がしていることは2つあります。カスタム形状の描画と.pngファイルからのビットマップの読み込み。
次の行は、ロード時にファイルをロックします(これは望ましくないシナリオです)。
Bitmap bmp = new Bitmap("file.png");
だから私はビットマップをロードする別の方法を使用しています。
public static Bitmap LoadBitmap(string path) {
using (Bitmap original = new Bitmap(path))
{
return new Bitmap(original);
}
}
これはかなり遅いと思いますが、ファイルのロックをすばやく解除しながら画像をロードするためのより良い方法はわかりません。
今、画像を描くとき、私が使う方法があります:
public void Draw() {
Bitmap bmp = new Bitmap(240,320);
Graphics g = Graphics.FromImage(bmp);
// draw something with Graphics here.
g.Clear(Color.Black);
g.DrawImage(Images.CloseIcon, 16, 48);
g.DrawImage(Images.RefreshIcon, 46, 48);
g.FillRectangle(new SolidBrush(Color.Black), 0, 100, 240, 103);
pictureBox.Image = bmp;
}
ただし、これは何らかのメモリリークのようです。そして、それをあまりにも長く続けていると、アプリケーションは最終的にクラッシュします。
したがって、3つの質問があります。
1。)ファイルをロックせずにファイルからビットマップをロードするためのより良い方法は何ですか?
2。)メモリリークやObjectDisposedExceptionのスローが発生しないように、Draw()関数で手動で破棄する必要のあるオブジェクト(およびその順序)を教えてください。
。) pictureBox.Imageがコードの最終行のようにbmpに設定されている場合、pictureBox.Image.Dispose()は、pictureBox.Imageまたは基になるビットマップの維持に関連するリソースのみを破棄しますそれに設定?
1:Windows Mobileで動作するかどうかはわかりませんが、これを試してください。
_FileStream bitmapFile = new FileStream("mybitmap.bmp", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
Image loaded = new Bitmap(bitmapFile);
_
2:SolidBrush
は破棄する必要があります。処分には一般的なルールがあります。 -> "disposeを実装するすべてのオブジェクト(インスタンス化されたオブジェクト)は、オブジェクトis戻り値/参照値/出力値の場合を除いて、手動で破棄する必要があります"
この場合、using
ステートメントを使用することをお勧めします
_using (new objecttodispose){ ..... }
_
using
ステートメントは、どのような場合でも(例を除いて)Dispose()
の呼び出しを保証します。
3:Dispose()
は、ビットマップリソースを解放します。
実際のメモリリークはないと思います。問題は、古いビットマップを破棄しないことです。データをクリーンアップするのはGCです。しかし、決定的な方法はありませんwhenこれが発生します。
したがって、多くの画像をループ処理する場合は、メモリが増加し、別の時点で、1つの位置で落ちるか、抵抗することになると思います。
私はそれをテストしませんでしたが、おそらくこれはそれをより確定的にするのに少し役立つでしょう:
_public void Draw() {
Bitmap bmp = new Bitmap(240,320);
using(var g = Graphics.FromImage(bmp))
using(var solidBrush = SolidBrush(Color.Black))
{
// draw something with Graphics here.
g.Clear(Color.Black);
g.DrawImage(Images.CloseIcon, 16, 48);
g.DrawImage(Images.RefreshIcon, 46, 48);
g.FillRectangle(solidBrush, 0, 100, 240, 103);
//Backup old image in pictureBox
var oldImage = pictureBox.Image;
pictureBox.Image = bmp;
//Release resources from old image
if(oldImage != null)
((IDisposable)oldImage).Dispose();
}
}
_
そして、jack30lenaに触発された別のアイデア:
_public static Bitmap LoadBitmap(string path)
{
//Open file in read only mode
using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read))
//Get a binary reader for the file stream
using (BinaryReader reader = new BinaryReader(stream))
{
//copy the content of the file into a memory stream
var memoryStream = new MemoryStream(reader.ReadBytes((int)stream.Length));
//make a new Bitmap object the owner of the MemoryStream
return new Bitmap(memoryStream);
}
}
_
2番目のコードサンプルの背後にあるアイデアは、ファイルハンドルを削除して、ファイルの内容をメモリにコピーすることです。その後、ビットマップはoldImage.Dispose()
を呼び出すことにより、最初のサンプル内に配置されるMemoryStreamの所有権を取得します。
このアプローチを使用することで、メモリに2つを超える画像が存在することはなくなり、実際には、大きな画像または少量のRAMによってOutOfMemoryExceptionsのみが発生します。