ふとBitmapをDisposeしなかったらどうなるのかという疑問を抱きました。
たとえばこれはピクチャーボックス上をマウスが移動すると、ピクチャーボックス上に「マウスの座標は (X, Y)」と書かれたBitmapを生成します。そして通常はいらなくなったBitmapはDisposeしないといけないのですが、あえてしていません。しないとどうなるのでしょうか? またメモリーの消費量が増えていくのがわかりやすいように不必要に大きなサイズのBitmapを生成しています。
1 2 3 4 5 6 7 8 9 10 11 12 |
Bitmap CreateBitmapFromMousePos(MouseEventArgs e) { string x = e.X.ToString(); string y = e.Y.ToString(); string str = "マウスの座標は (" + x + ", " + y + ")"; Bitmap bitmap = new Bitmap(pictureBox1.Width * 5, pictureBox1.Height * 5); Graphics g = Graphics.FromImage(bitmap); g.DrawString(str, new Font("MS ゴシック", 20), new SolidBrush(Color.Red), new Point(10, 10)); g.Dispose(); return bitmap; } |
以下のコードは生成されたBitmapをPictureBox1.Imageにセットしています。それまでセットされていたものはDisposeしなくていいのでしょうか?
1 2 3 4 5 |
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { Bitmap bitmap = CreateBitmapFromMousePos(e); pictureBox1.Image = bitmap; } |
上記コードを実行すると急激にメモリーの使用量が増えますが、すぐに戻ります。ガベージコレクタが機能しているのではないかと思います。
では以下のコードはどうでしょうか? 処理のたびにGC.Collect();を実行しています。これだとメモリーが急激に増えることはありません。pictureBox1.Imageにこれまでセットされていた古いBitmapがガベージコレクタによって回収されているから・・・なのでしょうか?
1 2 3 4 5 6 7 |
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { Bitmap bitmap = CreateBitmapFromMousePos(e); pictureBox1.Image = bitmap; GC.Collect(); } |
ガベージコレクタには安易に頼るのはどうなのでしょうか? そこで以下のコードであればどうでしょうか?
これも上記と同じで急激にメモリーの使用量が増加することはありません。これが一番よいのでしょうか?
1 2 3 4 5 6 7 8 9 |
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { Bitmap bitmap = CreateBitmapFromMousePos(e); Bitmap oldBitmap = (Bitmap)pictureBox1.Image; pictureBox1.Image = bitmap; if(oldBitmap != null) oldBitmap.Dispose(); } |
それから以下のようなコードも試してみました。今度はフィールド変数のBitmapsに生成したBitmapが格納されていきます。実行してみるとメモリーの使用量はどこまでも増え続けます。生成したBitmapをBitmapsに格納しているのでガベージコレクタに回収されることはないからです。
1 2 3 4 5 6 7 8 9 10 |
List<Bitmap> Bitmaps = new List<Bitmap>(); private void pictureBox1_MouseMove(object sender, MouseEventArgs e) { Bitmap bitmap = CreateBitmapFromMousePos(e); Bitmap oldBitmap = (Bitmap)pictureBox1.Image; pictureBox1.Image = bitmap; Bitmaps.Add(bitmap); } |
しかし以下を実行すればメモリーの使用量は元に戻ります。
1 2 3 4 5 6 7 |
private void button1_Click(object sender, EventArgs e) { foreach(Bitmap bitmap in Bitmaps) bitmap.Dispose(); Bitmaps.Clear(); } |
ピクチャーボックスに生成されたBitmapを次々とセットする処理をすることは多いと思われます。少なくとも私はよくやります。やはり古いPictureBox.ImageをDisposeするのがよいと思われます。面倒くさいときはGC.Collect()でお茶を濁すこともあるかもしれませんが・・・。