- PR -

.NETでもメモリリーク?

投稿者投稿内容
未記入
ぬし
会議室デビュー日: 2002/03/28
投稿数: 255
投稿日時: 2002-11-18 10:49
>やはり、「自分で解放できない」というのは、私にとっては、とても大きな障害で
>あると感じます。

多分,GCのことを,「全然」理解していないだけでしょう.
#「解放」という単語の定義にもよるけど.

Javaの場合,free()やデストラクタはないですが,インスタンスを解放する/インス
タンスを参照可能でないようにするのはプログラマーの仕事です.これはGCがあっても
関係ありません.

GCでは「回収するタイミング」がlazyになるだけで,インスタンスが死ぬのは
プログラマーに依存する.問題なのはインスタンスが生きたままほったらかし
にしているプログラマーがいる場合の話.しかし,最悪でも全ての参照を
クリアすれば,全てのインスタンスが回収されることは保証されます.

これに対し,GCが無い場合では,参照(ポインタ)を解放し忘れた場合は(そして
これは決して珍しくない話なのだが,)メモリリークが発生し,たとえ少しずつ
だとしても,確実にメモリを食い潰していって,いずれは動作不能になります.

>しかし、WindowsServiceなど、長期間にわたって無休で動作するものがいつ破棄される
>かわからないのでは、特にGBオーダーのメモリをアロケートしても(って、2GBまで
>でしたよね、確か)さらにもっと要求する、しかもそのほとんどは開発者の意図では
>すでに解放済みである、というのは、どうでしょう?
発想がまるで逆ですね.

たしかに,明示的にデストラクタやfree()を呼び出すプログラミングスタイルでも,
「人間が絶対に間違いをしない限り」動作します.ですが,人間は間違える動物で
あり,これは言い換えれば「必ず動作しない」と同義と言って良いでしょう.この
ような「プログラマーが絶対に間違いをしない」というありえない仮定を要求する
プログラミングスタイルでは,いつまで立ってもバグは取れません.WindowsNT系の
不安定さとサーバーサイドJavaの安定性が,事実上それを証明しています.
#バッファオーバーフローの場合も同様.Javaではランタイムにバグが無い限り,
#理論上発生しない.

それに「開発者の意図において解放済み」とはいうものの,メモリリークとはまさに,
「開発者の意図において解放済み」である(しかし実際には解放するのを忘れている)
メモリが永久にメモリを占有しつづける現象ですよ?

GCの有無に関係なく,プログラマーは全て解放した「つもり」でも,一つや
二つのインスタンスの解放を忘れるのはよくある話です.それも毎回動くメイン
ループならともかく,何時間かに一回しか動かないような部分では,そのメモリ
リークを発見することさえ困難です.しかもなまじポインタを上書きして消して
しまえば,free()を呼び出すことさえできないでしょうしね.

で,GCの場合ならば参照さえ消しておけば,後はほっといても勝手に回収して
くれます.「不要な参照は消せ」というルールさえ守っておくだけでよいので,
プログラミングが遥かに楽で,しかも安全です.
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2002-11-18 11:51
NothingBut.NETFXさん

>>このコメントは、要するにこのスレにつけられた善意のコメントが参照している情報も、
>>それらの方々が回答するにあたって考えられた基盤となっているものも、
>>「所詮MSだから」無意味だということでしょうか。
>>Jittaさんの周 囲がどうであるかは存じませんが、
>>それで済む話ならどうしてこの場に問題提起をされたのでしょうか。

 無意味とは考えていません。無意味であるならレスをつけたり参照先を見て回ったりしません。解決したいし、自分で解決の糸口が見つけられなかったから上げているのです。たとえば、ご呈示いただいたツールも、私だって一応はサーチかけました。しかし、私は英語は一般的な文を読むことまでしかできないので、「Allocate」とか「profile」でサーチすることが思いつかないのです。それで、「メモリ」「リーク」とかで検索しても、VC系の話しか出てこないのです。英語まで頭が回ってませんでしたが。
 「所詮MS」は、最後の最後の結論です。その結論に行き着くまではジタバタします。不快感を与えたことは申し訳なく思いますが、私だってそんな言葉で終わらせるのは不快なのです。
 そのことですが、私は「」を「自嘲」の意味で使っているのですが、「嘲笑」は他人に対して、になりますね。これは以後やめます。これも日本とアメリカの文化の違いについて理解していないため、と、とらえてください。失敗したときに「えへっ、失敗しちゃった」とやりますよね。その意味でベロ出しを探していて、たまたまどこかで見かけてつかっていました。


 ご呈示いただいたツールですが、WindowsServiceでは使えないようでした(付属文書を隅から隅まで読んだわけではないですが)。「Serviceを起動するにはコントロールツールから」というメッセージが出ます。WindowsApplicationへ換装し、もう一度試してみます。
未記入
ぬし
会議室デビュー日: 2002/03/28
投稿数: 255
投稿日時: 2002-11-18 12:21
>(GC.CollectでGCが呼び出せるなら、結局FreeなりDeleteしているのと同じですよね)
多分ですが,全然違うと思います.

多分,これはJavaのSystem.gc()に相当するものだと思うけど,それは通常ならlazyに
呼び出されるはずのGCを強制的に呼び出すだけのものです.

GCの動作としては,大抵の場合は,
「インスタンスが生成/終了 →ある程度ゴミが溜まる→ GCが動いてゴミを捨てる」
のサイクルを繰り返す,という風にイメージすれば大体あってます.

System.gc()は,ゴミが溜まる前にGCを強制的に起動したい場合に使うだけの
ものに過ぎず,動作の本質は変わりません.正常なプログラムならば,
System.gc()を呼び出そうが呼び出すまいが,同じように正常に動作します.

>しかし、WindowsServiceなど、長期間にわたって無休で動作するものがいつ破棄される
>かわからないのでは、特にGBオーダーのメモリをアロケートしても(って、2GBまで
>でしたよね、確か)さらにもっと要求する、
GCでは回収のタイミングは明示されませんが,それは最適化のためです.いくらでも
メモリを要求するわけじゃありません.実行タイミングは実装依存とはいえ,通常は
インスタンスでメモリを食い潰す前に(上のサイクルで言えば「ある程度」ゴミが
溜まった時点で)GCが起動して,インスタンスを解放します.

無制限に消費しているとすれば,
1,「生きている」インスタンスだけで無制限にメモリを消費している.
#例えば,100GBの大きさの配列か何かをnewしようとしたらどうなります?
2,ランタイム側のバグ
のいずれかです.

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2002-11-18 13:13
※調査の途中経過※

 「GC.Collect」を明示的に呼ぶことで、減ることのなかった「メモリ使用量」が減りました。

 ただ、起動時の状態までは下がらないため、「参照外し抜け」がないか、もう一度見直します。

※追加※
 起動時の状態まで下がらないのは、デバッガでアタッチしたからのようです。メモリ使用量の峠と谷がほぼ一致して動作しています。
 ちなみに、ソースの方は元のものに、Timerのインターバル待ちに入る前に GC.Collnect を追加しただけです。
 このまま、インターバルが5分だったのを10秒にして、1時間ほど実行させて結果を見ます。

[ メッセージ編集済み 編集者: Jitta 編集日時 2002-11-18 13:47 ]
1時間たっていませんが、45分ほど経過した状態で、谷のメモリ使用量が23,636KBでした。もう一度、GC.Collectを外してやってみます。

[ メッセージ編集済み 編集者: Jitta 編集日時 2002-11-18 14:30 ]

※GC.Collectを外したところ※
 メモリ使用量が100MB位になると30MB近くにまで下がりました。13日に確認した、「下がらない状態」を残していないこと、13日には60秒に1回の処理を今回は10秒に1回にしたことから、私の確認不十分であったと判断します。

 ご迷惑をおかけしました。

[ メッセージ編集済み 編集者: Jitta 編集日時 2002-11-18 17:19 ]

スキルアップ/キャリアアップ(JOB@IT)