VC++(Windows)でのガベージコレクション機能について

[戻る]
とよ 2009/09/12(土) 11:55:47
 VC++2005でソフトウェアを作っているものです。

 多数の文字列をアプリ立ち上げ時にINITファイルから読み込み、メモリに動的に割り
当てて終了時まで使用しています。動的に確保した文字列は終了時にdeleteしていませ
ん。ここで質問ですが、

 「C言語ポインタ完全制覇」という本のP128にて、

・PCで普通に使われているOSなら、プロセス終了時にアプリケーション領域を確実に
 解放してくれます。(←OSのガベージコレクション機能と解釈しています)

と書いてあって、今回のケースは「手を抜いていい部分」と判断していいのかな〜
と思っていますが、どうでしょうか?アプリを何度立ち上げなおしても、メモリリーク
しないと考えてよいでしょうか?
 
 まず何より、ガベージコレクションというとJAVAの言語としての機能と思っていて
(JAVAはできません)、OSにこんな機能があるならJAVAのガベージコレクションって何の
意味があるんだろうかなどと考えてしまいました。OSにガベージコレクション機能が
ない時に、言語のガベージコレクション機能が力を発揮するんですかね?

 とりとめの無い話で申し訳ないですが、ご意見お願いします。

ITO 2009/09/12(土) 13:27:32
そう思ったら、実際に試してみるのがいいと思います。

 1. 簡単な試作版を作る。
 2. デバック→開始を行なう。
 3. 試作版に必要な操作を行なう。
 4. 適当なタイミングで終了する。
を行なったあと
デバッグウインドウに「Memory Leak」のコメントが出なければOKです。

Ban 2009/09/12(土) 13:37:11
> 今回のケースは「手を抜いていい部分」と判断していいのかな〜と思っていますが、
> どうでしょうか?

特に背景情報もなしに私が判断するなら、バグとしてNGといいます。
# (deleteとあるのでC++なら)せめて文字列はstd::string(やCString)などにするとか
# 簡易にできる手は打つべきだと思います。何か特殊事情があれば個別判断でしょうが。

とはいえ、起動時に確保するのみで動作中に動的に増減しないなら、
その程度の品質要求(動けばいいという考え…)だという割り切りで
手を抜くという判断をする人がいても驚きはしません。(私はいやですが…)

> アプリを何度立ち上げなおしても、メモリリークしないと考えてよいでしょうか?

飲んで放置した空き缶をその場所の管理人に捨てさせるとか、
借金を返さずに担保の強制執行で家が更地になるとか、そんなイメージでしょうか。

*言語仕様的には*保証がないですが(プログラム終了時に解放されるとは書いてない)、
VC2005の対象環境なら、OSの方ではメモリを強制的に回収すると期待できるでしょう。


> ガベージコレクションというとJAVAの言語としての機能と思っていて
Java以外にもあります。

> OSにガベージコレクション機能がない時に、
> 言語のガベージコレクション機能が力を発揮するんですかね?

OSのリソース回収はどちらかというと、先にも書いたように「強制執行」です。
どれが不要でどれが必要かも判断できないので、アプリが動いている間は基本的に役に立
ちません。
(監視はされても救済はありません。
一方、Java等のガベコレ(略)は、アプリ動作中でも不要になれば適宜動作します。


つまり、例えばあなたの部屋がゴミ屋敷状態でも、室内に収まっている限りはOSは何もし
てくれません。

OSは、それがあふれて近隣の迷惑になったらあなたを追い出したり、
もしゴミを残した失踪した場合に部屋ごと整理/処分するイメージです。
# 「敷金払ってるし引越前に掃除なんかしなくても大家がやるさ」<割り切り/手抜き
# そして大家ことOSは不要になったメモリを無条件に全て回収します。

一方、ガベコレはあなたに明らかに不要なもの(使ってないもの)を適宜選別して
捨ててくれる機能です。例えば親族や清掃業者などのイメージでしょうか。

アプリケーションを終了せずにメモリを確保している場合には、
メモリ不足で破綻するまで放置するOSよりも、
使い終われば適宜回収してくれるガベコレが便利で安全といわれるわけです。
# C++で"RAII"を守っていてもガベコレと同じような効果は得られます。

Ban 2009/09/12(土) 13:54:28
# メモリの回収はOS任せにして解放の手が抜きたいそうなので、
# 仮にアプリでMemory Leaksと出ても無視する前提なんだと思いますが…。

> 1. 簡単な試作版を作る。
> 2. デバック→開始を行なう。
> 3. 試作版に必要な操作を行なう。
> 4. 適当なタイミングで終了する。
> デバッグウインドウに「Memory Leak」のコメントが出なければOKです。

[勝手な補足]
上記がデフォルトで有効なのは「MFCを使った時だけ」です。
非MFCのWindowsアプリや、コンソールアプリなどでは、
明示的に有効にしない限りオフなので、仮に漏れていても上記コメントは出ませんので、
もし試す場合は、_CrtSetDbgFlagや_CrtDbgReport等を使ってやってください。
http://msdn.microsoft.com/ja-jp/library/1666sb98(VS.80).aspx

とよ 2009/09/12(土) 13:56:31
 ITOさん、Banさん、ありがとうございます。

 Banさんの例え話で、すごく罪悪感を感じてしまうのは私だけでしょうか・・・?
人のソースのお手伝いをしてまして、さらにCStringが使えないという事情がありま
して、ゴミ屋敷にあがりこんで、さらにごみを捨てて帰っているような感じです。片付
けるのには気合がいるのと時間が無いのとで「そのまま出荷で後知りませ〜ん」とい
うスタンスだったので、そこから改めようと思います。


> デバッグウインドウに「Memory Leak」のコメントが出なければOKです。

 確認してみます。

> 一方、Java等のガベコレ(略)は、アプリ動作中でも不要になれば適宜動作します。

 アプリ動作中に不要と判断できるということは、「ローカル変数でNewした後、関数
を抜けたとき」のような場合に自動解放してくれるような感じでしょうかね。C++でも
そのような機能があれば使いやすそうですね。

> 例えば親族や清掃業者などのイメージでしょうか。

 自分の部屋くらいは自分で片付けられるような人間であるよう心がけたいと思いま
す。

 "RAII"は初耳なので調べようと思います。

とよ 2009/09/12(土) 14:07:50
[[解決]]
 チェック忘れました。ありがとうございました。

Ban 2009/09/12(土) 14:11:17
> Banさんの例え話で、すごく罪悪感を感じてしまうのは私だけでしょうか・・・?

そういう例えをあげていると言うのもあります。
勿論本当にやむをえない事情もありえるとは思います(事故とか病気とか)。
お手伝い大変そうですががんばってください。

> 「ローカル変数でNewした後、関数を抜けたとき」のような場合に自動解放してくれる
ような感じでしょうかね。

そんな感じです。例えば参照数を把握していると参照されなくなったら不要とわかりま
す。

> C++でもそのような機能があれば使いやすそうですね。

RAIIってのは、近しい事を実現するテクニック?考え方?です。
プログラマが自分で明示的に/個別にdeleteを読んで回らなくて良いようになります。

例えば、C++言語仕様にも<memory>ヘッダにstd::auto_ptrってのがあります。
これは複製したりスコープを抜けるとデストラクタで自動的にdeleteしてくれます。
また、C++の次期仕様では参照数まで管理してくれるshared_ptrが採用される予定です。
他にも、new[]の代わりにstd::vectorを使えば同様にデストラクタでdeleteしてくれま
す。
char配列の変わりにstd::stringを使えば同様に…。
FILE*の代わりにfstreamを使えば同様に…。
(以下略

ITO 2009/09/12(土) 15:27:20
Banさん、補足ありがとうございます。
MFCを使ったときだけですか。
_CrtSetDbgFlagや_CrtDbgReport等ですね。
FrameWork等を使う時など試してみます。
とよさんも注意してください。

wclrp ( 'o') 2009/09/12(土) 21:51:41
変な例え話はいらん。

PATIO 2009/09/14(月) 13:17:41
まあ、たとえ話に関しては個々人の考え方も反映されるので
これはこれかなと思いますが。

すでに話は終わっているみたいですが、

私個人としては、OSが開放してくれると言うのは
あくまでもフェイル・セーフの為の物でこれを最初から当てにすべきではないと思います。
基本的には自分で始末するけれど、うっかり忘れた時の為の保証みたいなものではないか
なと。
後始末をすると言うのはプログラミングでもとても大切で、
各モジュールとか各関数で何処まで保証して何処まで処理するのか
という考え方はとても大事だと思うので仮にOSが最終的な後始末を
してくれるとしても、それは考えの中からは外すべきかなと思います。
この辺の処理の切り分けと保証の範囲がしっかりしていないと
モジュールを組み合わせた時に破綻します。

古いスレッドには追加発言できません。