質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

52070閲覧

C#でBitmapをDisposeできずにメモリが増えていくのを対処したい

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2016/09/29 09:43

編集2016/09/29 09:55

C#のBitmapのDisposeについて質問です。

pictureBoxに画像を表示して、Button1を押すと1pixel拡大するというコードを記述しました。

c#

1// Button1クリックイベント 2private void button1_Click(object sender, EventArgs e) { 3 Bitmap img = (Bitmap)pictureBox1.Image; 4 pictureBox1.Image = ScaleBmp(img); 5} 6 7// 元のBitmapを引き数に渡すと1pixel拡大したBitmapを出力する 8private Bitmap ScaleBmp(Bitmap src){ 9 Bitmap bmp = new Bitmap(src.Width + 1, src.Height + 1); 10 using (Graphics g = Graphics.FromImage(bmp)) { 11 g.DrawImage(src, 0, 0, src.Width + 1, src.Height + 1); 12 } 13 return bmp; 14}

このButton1を連続で何回も押すとプロセスメモリがどんどん増えていきます。
ScaleBmp関数の中でBitmapを生成してreturnしているので使用メモリが増えるのは当然なのですが巨大な画像の場合はものすごい勢いで増えていきます。

BitmapをpictureBox1.Imageに渡している場合、DisposeするとエラーになるためにDisposeすることができず、メモリが増えてしまいます。

しばらく放置すると.NetFrameworkが勝手にどこかでGCを実行するので不要になったBitmapが解放されるのですが、Button1を連打すると解放される前にメモリリークを起こしそうで困っています。

button1_Click関数の中の最後にGC.Collect()を実行すればいいのかとは思いますが、Button1を連打する度にGCを呼ぶのもよくないと思ってしまいます。

何か対策はありますでしょうか?
どうぞよろしくお願い致します。

Windows10 + VisualStudio2015 C#

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hihijiji

2016/09/29 09:55

pictureBox1.Image = ScaleBmp(img); //の後に img.Dispose(); // ←追加 するだけじゃダメですか?
退会済みユーザー

退会済みユーザー

2016/09/30 01:36

ありがとうございます、それで大丈夫でした!
guest

回答1

0

ベストアンサー

これで改善しませんかね?
var oldImage = pictureBox1.Image;
pictureBox1.Image = ScaleBmp(img);
oldImage.Dispose();

投稿2016/09/29 10:00

編集2016/09/30 01:19
ishi9

総合スコア1294

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/09/29 10:18

ありがとうございます。 てっきりScaleBmp関数内のBitmap bmp = new Bitmapで生成しまくっているほうがメモリを増やしているとばかり思っていました・・・。 そちらでメモリは増えなくなりました・・・!
ishi9

2016/09/30 01:12

いや、それで合ってます。メモリの増大分はそれです。 というか考え方的にも手順的にも概ね合ってます。 唯一の問題はここで >>BitmapをpictureBox1.Imageに渡している場合、DisposeするとエラーになるためにDisposeすることができず、メモリが増えてしまいます。 これのせいで開放処理ができなくなってしまっていたのが問題です。 pictureBox1.Image = ScaleBmp(img); これだけだと古いBitmapは参照から外れるだけで開放されません。(いつかはGCによって開放されますが)
退会済みユーザー

退会済みユーザー

2016/09/30 01:35

再度ありがとうございます。 var oldImage = pictureBox1.Image; pictureBox1.Image = ScaleBmp(img); oldImage.Dispose(); ですが、2行目の引数は pictureBox1.Image = ScaleBmp(oldImage); ですよね・・・? それといまいちわからないのですが、ScaleBmp関数内でnewで生成されたBitmapがどこで開放されているのかわかりません・・・。 ScaleBmp関数内で生成されたBitmapはpictureBox.Imageに渡りますが、ボタンを再び押すとまた生成されます。つまりその前に生成されたBitmapはどこで開放されているのでしょうか?
ishi9

2016/09/30 02:29

>>pictureBox1.Image = ScaleBmp(oldImage); すいません、そうでした。 >>ScaleBmp関数内で生成されたBitmapはpictureBox.Imageに渡りますが、ボタンを再び押すとまた生成されます。つまりその前に生成されたBitmapはどこで開放されているのでしょうか? 以前のコードだと一切開放されていません。完全放置状態です。 そして、それが今回のメモリ増大の原因です。 例えば、例を挙げると、こんな感じでしょうか void Func () { Bitmap image1 = (Bitmap)pictureBox1.Image; var image2 = ScaleBmp(image1); pictureBox1.Image = image2; var image3 = ScaleBmp(image2); pictureBox1.Image = image3; ・ ・ 以下繰り返し } こんな感じでimage1~10000000と処理を増やしていったらどうなるでしょうか? 当然、すぐにメモリオーバーしますよね?image2も3もそれ以降も全部 実際にBitmap持ってるわけですから。 前の処理はまさにこんな感じでした。 それを今回はこのように直しました。 void Func () { Bitmap image1 = (Bitmap)pictureBox1.Image; var image2 = ScaleBmp(image1); pictureBox1.Image = image2; image1.Dispose(); // ※1 var image3 = ScaleBmp(image2); pictureBox1.Image = image3; image2.Dispose(); // 上に同じ ・ ・ 以下繰り返し } ※1 image1.Dispose(); // pictureBox1.Imageはimage2に新しく置き換わってimage1を使わなくなったので、古いイメージであるimage1は開放する
退会済みユーザー

退会済みユーザー

2016/09/30 04:28

非常にわかりやすいご説明をありがとうございます! とても納得できました! Idisposableのあるオブジェクトは開放をきちんとしないとどんどんメモリが増えていきますね・・・。 今回の件で理解できましたので本当に助かりました。 ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問