- PR -

GetTotalMemoryのメモリ使用量とタスクマネージャのメモリ使用量について

投稿者投稿内容
カタナ
大ベテラン
会議室デビュー日: 2006/05/25
投稿数: 110
投稿日時: 2007-05-08 13:47
いつもお世話になります。
現在VB.NETを用いて運用を行なっているWindowsアプリケーション(basp21を利用して定期的にメールを受信して転送する仕組みのもの)で、メモリリークを起こしていました。
そこで調査した結果、次の処理を追加することでメモリの使用量は激減しました。
basp=nothing
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
System.GC.Collect()

ただし激減はしたものの、Windowsタスクマネージャーでメモリ使用量を確認すると、時間がたつと微妙(1時間で約200KB程)にメモリ使用量は増加しています。しかし、Console.WriteLine(System.GC.GetTotalMemory(False))でメモリを確認するとメモリ使用量は変化していません。

そこで教えていただきたいのですが、
@実際のメモリ使用量はタスクマネージャの値を信じればいいのでしょうか?またはGetTotalMemoryメソッドの値を信じればいいのでしょうか?
といいますのは、下記のURLにおいては、「GetTotalMemoryメソッドは、必ずしも正確な値ではない可能性があることを示唆している。」との記述があり、
http://www.atmarkit.co.jp/fdotnet/dotnettips/021gc/gc.html
下記のURLにおいては「NETにおいて実際に使用しているメモリのサイズを確認するには、GCクラス(System名前空間)のGetTotalMemoryメソッドを使用して計測する必要がある。」との記述があり分からなくなってしまったからです。
http://www.atmarkit.co.jp/fdotnet/vblab/appqa_01/appqa_01_01.html
AGetTotalMemoryでメモリ使用量が増えていない場合はタスクマネージャー上ではメモリが増加していても問題ないのでしょうか?
Bbasp21を使用した場合、メモリの開放に必要な特別な処理はありますか?


あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-05-08 16:06
.NETに関しては全くの無知なのですが、
回答がないようですので。

GCを実装したシステムでは、実際のヒープの使用状況はGC直後の容量が
アプリケーションが必要とする最低限のフットプリントになります。

GCはヒープの空きが無くなった時に自発的に回収する仕組みなので、
GCさえ起こらなければ時間が経つにつれて増えるのは当然です。

タスクマネージャとの食い違いを気にされているようですが、
こちらの数値はOSがプロセスに割り当てているページの合計なので、
事前に確保したヒープ上でやりくりしているGCとは食い違ってしまいます。

「GC」という仕組みについて勉強すれば自然と納得できると思いますよ。
じゃんぬねっと
ぬし
会議室デビュー日: 2004/12/22
投稿数: 7811
お住まい・勤務地: 愛知県名古屋市
投稿日時: 2007-05-08 16:24
タスクマネージャに表示されるメモリ使用量 [hatena.ne.jp]

_________________
C# と VB.NET の入門サイト
じゃんぬねっと日誌
カタナ
大ベテラン
会議室デビュー日: 2006/05/25
投稿数: 110
投稿日時: 2007-05-08 16:32
あしゅさん返信ありがとうございます。

>GCはヒープの空きが無くなった時に自発的に回収する仕組みなので、
>GCさえ起こらなければ時間が経つにつれて増えるのは当然です。
「GC」を自分なりに勉強しまして、メモリが不足してくれば、自動的に回収が行われるのでメモリが潤沢に余っている場合には、プロセスの使用するメモリ量が増加するのが正常な動作だということは理解しています。
http://www.atmarkit.co.jp/fdotnet/vblab/appqa_01/appqa_01_01.html
しかし、実際にメモリリークが起きてしまったので、ガベージコレクションが正常に動いていないのかと思い、System.GC.Collect()でガベージ・コレクションを強制的に実行しています。

>タスクマネージャとの食い違いを気にされているようですが、
>こちらの数値はOSがプロセスに割り当てているページの合計なので、
>事前に確保したヒープ上でやりくりしているGCとは食い違ってしまいます。
System.GC.Collect()でガベージ・コレクションを強制的に実行してもタスクマネージャでメモリ使用量は減らないものなのでしょうか?Timerで処理を実行しているのですが、実行後に毎回毎回メモリ使用量が若干とはいえ増えるのはそういうものなのでしょうか?

重ね重ね申し訳ありませんが、よろしくご教授ください。
ぽぴ王子
ぬし
会議室デビュー日: 2006/03/24
投稿数: 475
お住まい・勤務地: お住まい:城・勤務地:城
投稿日時: 2007-05-08 16:44
とりあえずタスクマネージャとメモリ使用量に関しては、じゃんぬさんの示し
てくださった NyaRuRu さんの日記を読んでいただくのがいいとして。

それよりもなによりも。

引用:

カタナさんの書き込み (2007-05-08 13:47) より:

現在VB.NETを用いて運用を行なっているWindowsアプリケーション(basp21を利用して定期的にメールを受信して転送する仕組みのもの)で、メモリリークを起こしていました。
そこで調査した結果、次の処理を追加することでメモリの使用量は激減しました。
basp=nothing
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
System.GC.Collect()


この時点で、メモリリークが起きている原因を調べて修正するのが一番先
なのではないでしょうか。
「メモリリークを起こしていました」ということは、どこかでメモリリークが起き
ていることは確認できているのでしょうから、その原因を調べて根絶しなけ
れば、GC をチョロチョロいじったぐらいの小手先のごまかしでなんとかなる
ようなものではないと思います。
(.NET アプリケーションで BASP21 を使ってしまう時点でどうか、という
 話もありますがそれはそれとして)
_________________
ぽぴ王子@わんくま同盟
ぽぴ王子の人生プログラミング中 / ぽぴンち。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2007-05-08 16:47
引用:

カタナさんの書き込み (2007-05-08 16:32) より:
しかし、実際にメモリリークが起きてしまったので、ガベージコレクションが正常に動いていないのかと思い、System.GC.Collect()でガベージ・コレクションを強制的に実行しています。


GCな環境でのメモリリークとは、不要なオブジェクトを参照し続ける事です。
わかりやすい例だと、寿命の長い配列の不要な要素をいつまでたっても
nullに設定しないような場合ですね。

このようなメモリリークが発生している状況では、
ある程度リークが続くとヒープの容量自体が拡張されます。
リークしているのでGCしても大して解放できなくなるので、
あきらめてヒープ容量自体を拡張するようになるからです。

それ以外で(Unmanaged Codeは除いて)メモリリークが起こるとすれば、
.NETランタイム自体のバグという事になるので、強制的にGCする必要は
GCに精通した開発者がパフォーマンス目的に行う以外にありえません。

引用:

System.GC.Collect()でガベージ・コレクションを強制的に実行してもタスクマネージャでメモリ使用量は減らないものなのでしょうか?Timerで処理を実行しているのですが、実行後に毎回毎回メモリ使用量が若干とはいえ増えるのはそういうものなのでしょうか?


ヒープとして一度確保された領域がOSに返却される事は滅多にありません。
.NETがどうなのかは知りませんが、実装されていないかもしれませんし、
実装されていてもそんなに頻繁に行われるものではありません。

GCは重い処理なので、処理中にメモリ確保が起こっても不思議はないでしょう。
カタナ
大ベテラン
会議室デビュー日: 2006/05/25
投稿数: 110
投稿日時: 2007-05-08 16:48
じゃんぬねっとさん返信ありがとうございます。

http://www.atmarkit.co.jp/fdotnet/vblab/appqa_01/appqa_01_01.html
http://d.hatena.ne.jp/NyaRuRu/20060730/p1
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=29586&forum=7
等を見て調べてはいるのですが、無知でして最終的によく分かりません。
結論としては次の私の認識はあっていますか?
@.NETのアプリケーションの場合にはタスク・マネージャで表示されているメモリ使用量は、実際に使用されているメモリ量とイコールではない。(タスク・マネージャに表示されるメモリ使用量は「ワーキング・セット」と呼ばれ、事前に確保されているメモリ領域に過ぎないから)
Aもしもメモリ使用量を見るのならば仮想メモリサイズと加算した値を見る必要がある。
(加算した値が増え続けている場合はメモリリークの可能性あり)
BGetTotalMemoryでメモリ使用量が増えていない場合はタスクマネージャー上ではメモリが増加していても問題ない
カタナ
大ベテラン
会議室デビュー日: 2006/05/25
投稿数: 110
投稿日時: 2007-05-08 17:05
ぽぴ王子さん、あしゅさん返信ありがとうございます。
お二人の返信で気づいたのですが、私がGCについて勘違いしているのでしょうか?

今回の修正の過程なのですが、
@メモリリークが起きている原因がbasp=nothingが入っていない為にオブジェクトの開放ができていないためだと思い、basp=nothingをロジックに追加しました。
Aただ、オブジェクトの開放を忘れていてもガベージコレクションで開放するはずなのに・・・と思い、ReleaseComObjectやSystem.GC.Collect()をロジックに追加しました。

▼最終的に追加したプログラムは、次のものです。
basp=nothing
Marshal.ReleaseComObject(basp)
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
System.GC.Collect()


そもそも使用されなくなったオブジェクトを自動的に解放する「ガベージ・コレクション」ではBaspなどのComオブジェクトは対象にならないのでしょうか?
あと.NET アプリケーションで BASP21 を使うのは良くないのでしょうか?標準のライブラリにはメール送信用はありますが、メール受信用が無いので、安易に使用してしまったのですが・・・。それがあだになってしまったようです。

私の返信がピンとはずれでしたら申し訳ありません。
よろしくご教授お願い致します。

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