DOBON.NET DOBON.NETプログラミング掲示板過去ログ

GCの動作について学ぶ良いサイトはありますか?

環境/言語:[VS2008 / C# / Windows7]
分類:[.NET]

DOBONに投稿することは初めてだったと思いますので、はじめまして。
howlingと申します。
普段VS2008 / C# / Windows7にてプログラミングをしております。

そこで、特にDisposeについて(メモリ管理についてと言った方が正しいかもしれません)、自分なりの理解が間違っていると思いますので、
できれば何かしらを通して学びたいと思っております。

例えば、他スレッドにて、Formインスタンスをひたすらnewし続けるとメモリを食うとありました。

---------------------------------------

//多分間違っている理解です。
void SomeFunction()
{
Form clsControlForm = new Form(); //1個分確保
}//ここのスコープを抜けた後のどこかでGCがclsControlFormを勝手に解放してくれると思っています。

void MainFunction()
{
SomeFunction();
}

---------------------------------------

特に、ImageやGraphics関連はDisposeを心がけているのですが、
なぜそこだけ心がける必要があるのかもわかっていません。
「IDisposableを実装する物は全てDisposeすべきもの」とどこかで書かれていたことがあったのですが、
それだとほとんど全てのクラスは解放処理をすべきということになる気がします。

このような事柄について
書籍/サイトでしっかり書かれているような良い場所はありませんでしょうか?

是非ご教授頂けますと幸いです。
■No30846に返信(howlingさんの記事)
> //多分間違っている理解です。
> void SomeFunction()
> {
> Form clsControlForm = new Form(); //1個分確保
> }//ここのスコープを抜けた後のどこかでGCがclsControlFormを勝手に解放してくれると思っています。

このサンプルコードだと、インスタンスを生成した後に何も処理がないので例としてあまり意味がないですね。
ちなみに変数の有効スコープ内であっても、(参照予定がなければ) GC の回収対象となることはありますよ。

> 特に、ImageやGraphics関連はDisposeを心がけているのですが、
> なぜそこだけ心がける必要があるのかもわかっていません。

メモリとリソースを区別して考えていないからでしょう。

> 「IDisposableを実装する物は全てDisposeすべきもの」とどこかで書かれていたことがあったのですが、
> それだとほとんど全てのクラスは解放処理をすべきということになる気がします。

ざっくり言えば、すべきもの、してもいいよの 2 点があります。
代表的なものとしては DataTable などの非接続オブジェクト。

> このような事柄について
> 書籍/サイトでしっかり書かれているような良い場所はありませんでしょうか?

今でいう MSDN フォーラムに .NET 当初に激論されたトピックがありますが、そこくらいですかね。
あとは Essential .NET のような .NET Framework としての内部的な実装について言及されている本を探すかくらいでしょう。
(私はあまり技術書を読む性質ではないので、申し訳ないですが詳しくないです)
■No30846に返信(howlingさんの記事)

参考書籍、サイトではないですが、

メモリという観点だけで見た場合、Managedのみ使用しているかUnManagedも
使用しているかということになると思います。ManagedはGCが管理しているメモリなのでGCが解放することが出来るのですが、UnManagedはGCの管理外なので解放することが出来ません。例えばFormはWindowsAPIにより作成されるのでUnManagedを使用しています。また外部IOアクセスを伴うものもWindowsAPIなのでUnManagedを使用することになります。GCも大分精度が上がってきてはいますが100%解放できるわけではないのでManagedであってもDisposeが必要な場合も出てきます。
>じゃんぬねっと様
ご返信頂きありがとうございます。
わんくま同盟ごく稀に勉強会参加してます。
今後ともよろしくお願いします。(掲示板早く直ると良いですが)

以下、引用にて失礼致します。

> ちなみに変数の有効スコープ内であっても、(参照予定がなければ) GC の回収対象となることはありますよ。

知りませんでした…。
こういうことをしっかり書いてある部分を知りたいんですよね。

> このサンプルコードだと、インスタンスを生成した後に何も処理がないので例としてあまり意味がないですね。

例えばファイルダイアログを開く場合とか、こういった形になったりするのかなと。
最近はメモリ解放の必要性うんぬんを考慮して、
usingを使用しているのでこうはなりませんが…。

> メモリとリソースを区別して考えていないからでしょう。

多分そうだと思います。
例えば、イベントの引数で送られてくるe.Graphicsは解放しないけれども、
CreateGraphicsで作成したGraphicsインスタンスは解放する…など、
いまいちよくわかっていない部分があり、悩んでいます。

> ざっくり言えば、すべきもの、してもいいよの 2 点があります。
> 代表的なものとしては DataTable などの非接続オブジェクト。

色々なサンプルコードを眺めていて、書いてある物に関しては必要なのかな?
という危険極まりない知識でいる感じです。

> 今でいう MSDN フォーラムに .NET 当初に激論されたトピックがありますが、そこくらいですかね。

FormインスタンスをShowしてCloseすることを繰り返すとメモリ使用量が増加している、とかでしょうか?
それであれば、チラっと見てから、尚の事メモリ管理の必要性があるのか悩むことになりました…。

> あとは Essential .NET のような .NET Framework としての内部的な実装について言及されている本を探すかくらいでしょう。

なるほど…。やはりかなり深い本になってしまいそうですね。
MSDNのクラス説明の始めあたりに、
「このクラスは○○した場合にはDisposeする必要があります」
くらいのことが書かれていればしっかり調べるんですが…今更ですよね。
Shu様

ご返信頂きありがとうございます。
ということは、気にならない程度にはメモリが使用されたままになっているということなのでしょうか?
C++のメモリリークのように(のようにと言っても、当然何を解放していないかによってサイズは全く異なりますが)、
アプリを24時間程度動かしていたら再起動してしまったりするレベルではない、
という認識で良いのでしょうか…?

これまでC++を使っていたのですが、近頃はC#を主体に使っております。
その理由として、インテリジェンスが(VS2008の話ですが)かなり良いのが一番の理由で、メモリリークすることが無い(GCが実装されている、というのが今となっては正しい理由ですが)ことが次の理由です。

インテリジェンスはC++も2010/2011 Betaでかなり強化されていると伺っておりますし、
メモリ解放の必要性まで出てくるようであれば、
C#の良さというのが自分なりにわからなくなってきてしまうと悩んでおります。

一体どのように書くべきなのでしょうか。
近頃では、デストラクタを作成してDisposeし始めている始末です。
(それはそれで良いことかもしれませんが)
■No30849に返信(howlingさんの記事)
> わんくま同盟ごく稀に勉強会参加してます。
> 今後ともよろしくお願いします。(掲示板早く直ると良いですが)

ご不便をおかけしておりましたが、先月くらいから復帰しています。

>>ちなみに変数の有効スコープ内であっても、(参照予定がなければ) GC の回収対象となることはありますよ。
> 知りませんでした…。
> こういうことをしっかり書いてある部分を知りたいんですよね。

有名なパターンとして Mutex + Application.Run メソッドのパターンで説明されます。
まあ、GC.KeepAlive しなくとも、Run メソッドの後に参照される予定のあるようなコード
(たとえば、Release するようなコードでも良い)
があれば、GC によって勝手に回収されなくなりますが。

> 例えばファイルダイアログを開く場合とか、こういった形になったりするのかなと。
> 最近はメモリ解放の必要性うんぬんを考慮して、
> usingを使用しているのでこうはなりませんが…。

まあ意識すべきリソースに関しては using を使うことになるので悩まなくともよろしいでしょう。

> 多分そうだと思います。
> 例えば、イベントの引数で送られてくるe.Graphicsは解放しないけれども、
> CreateGraphicsで作成したGraphicsインスタンスは解放する…など、
> いまいちよくわかっていない部分があり、悩んでいます。

それともまた少し違う気がしますが... (^^;
ぶっちゃけ通り道として、経験するしかないかもしれません。

基本的には作成した者が責任を持つという思想でよろしいかと思いますが、
落とし穴として有名なのは SystemBrush でしょうか、Dispose しちゃダメです。

> 色々なサンプルコードを眺めていて、書いてある物に関しては必要なのかな?
> という危険極まりない知識でいる感じです。

そのあたりは shu 様の説明がひとつの指標になると思います。
リソースとして管理すべきものでない場合は、放っておいても大丈夫ということにはなっています。
面倒みた方が良い場合もあるので、大丈夫ということになっていますとしか言えませんがw

> FormインスタンスをShowしてCloseすることを繰り返すとメモリ使用量が増加している、とかでしょうか?
> それであれば、チラっと見てから、尚の事メモリ管理の必要性があるのか悩むことになりました…。

もっと根本的な IDisposable インターフェイスについてのトピックだったと記憶しております。

> なるほど…。やはりかなり深い本になってしまいそうですね。
> MSDNのクラス説明の始めあたりに、
> 「このクラスは○○した場合にはDisposeする必要があります」
> くらいのことが書かれていればしっかり調べるんですが…今更ですよね。

IDisposable インターフェイスが実装されているもので、自分が作成したものであれば、
すべて using または Dispose してやるという思想でだいたい良いと思います。
(SystemBrush がダメなのも、自分で作成していないということで強引に説明はつくのかな?)

それと、

> インテリジェンス

インテリセンスではないでしょうか?
 Intelligence は「知識にまつわる情報」
 Intellisense は「マイクロソフトによる自動補完システム」
です。

> 近頃では、デストラクタを作成してDisposeし始めている始末です。

VC++ (プロジェクトのタイプにもよりますが) なら良いのですが、C# に対してではないですよね?
C# のデストラクタは「ファイナライザ」であり、GC に回収されたタイミングを示します。
C++ で言うところのデストラクタ (のタイミング) はありません。
じゃんぬねっと様

お返事頂きありがとうございます。
リソースのみ解放するということで、
一旦は解決ということにしたいと思います。
それ以外の場所でも、Disposeをある程度必要と感じた際には使おうと思います。

以下は引用にて失礼致します。


> ご不便をおかけしておりましたが、先月くらいから復帰しています。
そうなんですか!今後また使わせて頂くことになると思いますので、
その節はまた宜しくお願い致します。

> まあ、GC.KeepAlive しなくとも、Run メソッドの後に参照される予定のある
これはそうですよね…。
ですので、なんとなしに今後も参照できる状態で、かつ参照していれば良いのかなと思っています。

> まあ意識すべきリソースに関しては using を使うことになるので悩まなくともよろしいでしょう。

一旦はこれで解決ということで。

> ぶっちゃけ通り道として、経験するしかないかもしれません。

そうなりそうですね…。
既に何度か経験しているので、
その度に何か良いものはないのか…と思いつつ勉強にはなっております。

> そのあたりは shu 様の説明がひとつの指標になると思います。

そうなりそうですね。
あまり気にしすぎるのも良くなさそうですね。

> もっと根本的な IDisposable インターフェイスについてのトピックだったと記憶しております。

こちらは了解です。ではまた別件ですね。

> インテリセンスではないでしょうか?

本当ですね!!お恥ずかしい限りです…。
以後はインテリセンスで(苦笑

> C# のデストラクタは「ファイナライザ」

やはりそうですよね。
これも実は曖昧だったので非常に助かりました。
1度ファイナライザと記憶していたはずなのに、
C#で~クラス名と書くのはデストラクタと呼ぶという記載がありましたので、
自分が間違ったものだと思っていました。
ありがとうございました。



最後に、

コメント頂きました、じゃんぬねっと様、shu様、大変参考になりました。
ありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板