自作ツールを使ってた(+テスト中)時の話ですが、
間違えてものすごく大量のデータを
データグリッドに落としてしまったんです。
「うわー、大丈夫かコレ」
その時タスクマネージャーで確認してみると
メモリ使用量が200Mくらいで止まってました。
「あ、そだ。せっかくだからこのままほっといてメモリ量の検証してみようっと」
と思い立ち、取得したデータを上書きして
しばらくほっといたのですが
「全然減らねぇ」
おいおい、大丈夫かよ(;´Д`)
もしかして取得データがどこかに残っててメモリ回収されてないんじゃないの?
というわけ(?)で
データグリッド(正確にはデータセット?)の取得・クリアを繰り返し、
ガベージコレクトできちんと回収されてるかを検証してみました。
*注
メモリ量の取得には
GC.GetTotalMemory(false);
を使用しておりますが、必ずしも正確な値ではないらしいです
それでは以下を見ていきましょう。
画面の「トータルメモリ(初期値)」は、文字通り初期のメモリ値です。
その下の「トータルメモリ」が、その時点でのメモリを表します。
「トータルメモリ」の値に注目して下さい。
①初期画面。

まずは、クリアボタンで以下のコードを実行した後で
ガベージコレクトした場合を見てみましょう。
②データ取得直後のメモリ
(ちなみに、検証用データとして
約10万件のデータをデータベースから取得しています。
30Mくらい?)

そして、クリアボタンを押してからガベージコレクトした結果が③です。
③「クリア」→「ガベージコレクト」した直後のメモリ

②379MB→③243KB
と、だいぶ減りました。取得データが回収されたようです。
それでは次に、クリアボタンで以下のコードを実行した後で
ガベージコレクトした場合を見てみましょう。
④データ取得直後のメモリ

⑤「クリア」→「ガベージコレクト」した直後のメモリ

④360MB→⑤270MB
と、今回はあまり減りませんでした。
(_ds.Dispose();
や
_ds = null;
を入れても同じ結果にでした)
これ、どうして減らないのかはよくわかりません。
取得したTableやRowは参照外れてるんじゃないの?
どこかに残ってるの?
とりあえずメモリ上に残したくない時は
DataSourceにnullを設定しろということでしょうか。
じゃあ次に、
大きいデータを取得した後に小さいデータをバインドし直した時は
どうなるのか見てみましょう。
まず、10万件ほどのデータをバインドします。
⑥大きいデータ取得直後のメモリ

そして次に、1件だけバインドさせます。
⑦小さいデータ取得直後のメモリ

「382MB」→「383MB」
と、この時点ではメモリは減りません。
そして、上記からガベージコレクトした結果が⑧です。
⑧「ガベージコレクト」(×2)した直後のメモリ

大きいデータ分のメモリは回収されたようです。
ちなみに、ガベージコレクトは2回行わないと回収されませんでした。
世代管理とやらが関係してるとは思うのですが
GC.Collect();
って、すべての世代に対して回収するんじゃないの?
ようわからんの~
最後に
取得したデータをどんどん上書きしていった時のメモリも検証してみました。
38M(取得1回目)→78M(取得2回目)→110M(取得3回目)→145M(取得4回目)
と増やした後にガベージコレクトした結果、
145M→99M(GC1回目)→36M(GC2回目)…(以降変わらず)
とメモリが減っていきました。
う~ん、やっぱり世代毎に回収されるっぽいな。
まあそれはいっか。
今回の検証の結果、とりあえずデータグリッドをクリアしたい場合は
データソースにNullを入れるのが吉のようです。
というか、上書きでもいずれ消えそうだからそれでもいいんですけどね。
DataSetのClearメソッドでは何故ダメなんだろう…謎だ。
ああそうだ。
結局、自作ツールのメモリが減らないのはどうして?
という問いですが…
.NETとは
そういうもの
らしいですw
減らなくて正解。
ガベージコレクトして減っていれば問題ないということでしょう(多分)
しかしDisposeもそうだけど
メモリ管理本当わからんな~
…こんなんでいいのか?
間違えてものすごく大量のデータを
データグリッドに落としてしまったんです。
「うわー、大丈夫かコレ」
その時タスクマネージャーで確認してみると
メモリ使用量が200Mくらいで止まってました。
「あ、そだ。せっかくだからこのままほっといてメモリ量の検証してみようっと」
と思い立ち、取得したデータを上書きして
しばらくほっといたのですが
「全然減らねぇ」
おいおい、大丈夫かよ(;´Д`)
もしかして取得データがどこかに残っててメモリ回収されてないんじゃないの?
というわけ(?)で
データグリッド(正確にはデータセット?)の取得・クリアを繰り返し、
ガベージコレクトできちんと回収されてるかを検証してみました。
*注
メモリ量の取得には
GC.GetTotalMemory(false);
を使用しておりますが、必ずしも正確な値ではないらしいです
それでは以下を見ていきましょう。
画面の「トータルメモリ(初期値)」は、文字通り初期のメモリ値です。
その下の「トータルメモリ」が、その時点でのメモリを表します。
「トータルメモリ」の値に注目して下さい。
①初期画面。

まずは、クリアボタンで以下のコードを実行した後で
ガベージコレクトした場合を見てみましょう。
this.dataGrid1.DataSource = null;
②データ取得直後のメモリ
(ちなみに、検証用データとして
約10万件のデータをデータベースから取得しています。
30Mくらい?)

そして、クリアボタンを押してからガベージコレクトした結果が③です。
③「クリア」→「ガベージコレクト」した直後のメモリ

②379MB→③243KB
と、だいぶ減りました。取得データが回収されたようです。
それでは次に、クリアボタンで以下のコードを実行した後で
ガベージコレクトした場合を見てみましょう。
DataSet _ds = (DataSet)this.dataGrid1.DataSource; _ds.Clear();
④データ取得直後のメモリ

⑤「クリア」→「ガベージコレクト」した直後のメモリ

④360MB→⑤270MB
と、今回はあまり減りませんでした。
(_ds.Dispose();
や
_ds = null;
を入れても同じ結果にでした)
これ、どうして減らないのかはよくわかりません。
取得したTableやRowは参照外れてるんじゃないの?
どこかに残ってるの?
とりあえずメモリ上に残したくない時は
DataSourceにnullを設定しろということでしょうか。
じゃあ次に、
大きいデータを取得した後に小さいデータをバインドし直した時は
どうなるのか見てみましょう。
まず、10万件ほどのデータをバインドします。
⑥大きいデータ取得直後のメモリ

そして次に、1件だけバインドさせます。
⑦小さいデータ取得直後のメモリ

「382MB」→「383MB」
と、この時点ではメモリは減りません。
そして、上記からガベージコレクトした結果が⑧です。
⑧「ガベージコレクト」(×2)した直後のメモリ

大きいデータ分のメモリは回収されたようです。
ちなみに、ガベージコレクトは2回行わないと回収されませんでした。
世代管理とやらが関係してるとは思うのですが
GC.Collect();
って、すべての世代に対して回収するんじゃないの?
ようわからんの~
最後に
取得したデータをどんどん上書きしていった時のメモリも検証してみました。
38M(取得1回目)→78M(取得2回目)→110M(取得3回目)→145M(取得4回目)
と増やした後にガベージコレクトした結果、
145M→99M(GC1回目)→36M(GC2回目)…(以降変わらず)
とメモリが減っていきました。
う~ん、やっぱり世代毎に回収されるっぽいな。
まあそれはいっか。
今回の検証の結果、とりあえずデータグリッドをクリアしたい場合は
データソースにNullを入れるのが吉のようです。
というか、上書きでもいずれ消えそうだからそれでもいいんですけどね。
DataSetのClearメソッドでは何故ダメなんだろう…謎だ。
ああそうだ。
結局、自作ツールのメモリが減らないのはどうして?
という問いですが…
.NETとは
そういうもの
らしいですw
減らなくて正解。
ガベージコレクトして減っていれば問題ないということでしょう(多分)
しかしDisposeもそうだけど
メモリ管理本当わからんな~
…こんなんでいいのか?