プライベートバイト、仮想バイト、ワーキングセットとは何ですか?


491

perfmon windowsユーティリティを使用して、プロセスのメモリリークをデバッグしようとしています。

これは、perfmonが用語を説明する方法です。

ワーキングセットは、このプロセスのワーキングセットの現在のサイズ(バイト単位)です。ワーキングセットは、プロセス内のスレッドによって最近アクセスされたメモリページのセットです。コンピュータの空きメモリがしきい値を超えている場合、ページは使用されていなくてもプロセスのワーキングセットに残ります。空きメモリがしきい値を下回ると、ページはワーキングセットから削除されます。それらが必要な場合、メインメモリを離れる前に、ワーキングセットにソフトフォールトされます。

仮想バイトは、プロセスが使用している仮想アドレス空間の現在のサイズ(バイト単位)です。仮想アドレス空間の使用は、ディスクまたはメインメモリページの対応する使用を必ずしも意味しません。仮想空間は有限であり、プロセスはライブラリをロードする能力を制限する可能性があります。

Private Bytesは、このプロセスが割り当てた、他のプロセスと共有できないメモリの現在のサイズ(バイト単位)です。

これらは私が持っている質問です:

共有ライブラリが関与していないためプロセスにリークがあるかどうかを確認するために測定する必要があるのはプライベートバイトですか?リークが発生した場合、プロセス自体から発生しますか?

プロセスによって消費されるメモリの合計はどれくらいですか?それは仮想バイトですか、それとも仮想バイトとワーキングセットの合計ですか?

プライベートバイト、ワーキングセット、仮想バイトの間に何か関係がありますか?

メモリ使用量をよりよく把握できる他のツールはありますか?


3
優れたツールはvalgrind / helgrindですが、残念ながらWindowsにはありません:(
Kornel Kisielewicz

それはプロセスが任意のリークを持っている場合はプライベートバイトが、私は確かに測定すべきであるである 場合はプライベートバイトプロセスのあなたは何のメモリリークを持っていない、その後成長しません。大きくなった場合は、メモリリークやメモリの断片化が原因である可能性があります。プライベートバイトの増加を見ても、その意味を正確に説明するのは難しいと思います。

@SergeiKurenkov私たちが言えることの1つは、「メモリの断片化」が原因では決して起こらないということです。
Jamie Hanrahan、2018年

回答:


517

この質問の簡単な答えは、これらの値はどれも、実行可能ファイルが実際に使用しているメモリの量を示す信頼できる指標ではなく、メモリリークのデバッグに本当に適切なものではないということです。

Private Bytesは、プロセス実行可能ファイルが要求したメモリの量を示します。必ずしも実際に使用している量ではありません。それらは(通常)メモリマップファイル(つまり共有DLL)を除外するため、「プライベート」です。しかし、ここが問題ですこれらのファイルによって割り当てられたメモリが必ずしも除外されるわけではありません。プライベートバイトの変更が実行可能ファイル自体によるものか、リンクされたライブラリによるものかを判断する方法はありません。プライベートバイトも物理メモリだけではありません。それらはディスクまたはスタンバイページリストにページングできます(つまり、使用されていませんが、まだページングされていません)。

ワーキングセットは、プロセスによって使用される物理メモリ(RAM)の合計を指します。ただし、プライベートバイトとは異なり、これにはメモリマップファイルやその他のさまざまなリソースも含まれるため、プライベートバイトよりも正確な測定ではありません。これは、タスクマネージャーの「Mem Usage」で報告される値と同じであり、近年、無限の混乱の原因となっています。ワーキングセットのメモリは、ページフォールトなしでアドレスできるという意味で「物理的」です。ただし、スタンバイページのリスト物理的にはメモリ内にありますが、ワーキングセットでは報告されません。そのため、アプリケーションを最小化すると、「メモリ使用量」が突然低下する場合があります。

仮想バイトは合計ですプロセス全体が占める仮想アドレス空間です。これは、メモリマップトファイル(共有DLL)が含まれているという意味でワーキングセットに似ていますが、スタンバイリストのデータと、すでにページアウトされていて、ディスクのどこかにあるページファイルにあるデータも含まれています。負荷が高いシステムのすべてのプロセスで使用される仮想バイトの合計は、マシンの実際のメモリよりもかなり多くのメモリになります。

したがって、関係は次のとおりです。

  • Private Bytesは、アプリが実際に割り当てたバイトですが、ページファイルの使用を含みます。
  • ワーキングセットは、非ページのプライベートバイトとメモリマップファイルです。
  • 仮想バイトは、ワーキングセットとページ化されたプライベートバイトおよびスタンバイリストです。

ここに別の問題があります。共有ライブラリがアプリケーションモジュール内にメモリを割り当てることができるのと同じように、アプリのプライベートバイトで誤検知が報告される可能性があるのと同様にアプリケーションも共有モジュール内にメモリを割り当てて、falseにつながる可能性がありますネガ。つまり、アプリケーションがメモリリークを起こして、プライベートバイトにまったく現れない可能性があります。可能性は低いですが、可能です。

プライベートバイトは、実行可能ファイルが使用しているメモリ量の妥当な概算であり、メモリリークの潜在的な候補のリストを絞り込むのに役立ちます。数が絶え間なく無限に増加しているのを見た場合は、そのプロセスにリークがないか確認する必要があります。しかし、これは証明できませんリークがあるかどうかは。

Windowsでメモリリークを検出/修正するための最も効果的なツールの1つは、実際にはVisual Studioです(リンクは、製品ページではなく、VSを使用したメモリリークのページに移動します)。 Rational Purifyは別の可能性です。Microsoftには、この問題に関するより一般的なベストプラクティスドキュメントもあります。この前の質問には、より多くのツールがリストされています

これでいくつかの問題が解決することを願っています!メモリリークを追跡することは、デバッグで行うのが最も難しいことの1つです。幸運を。


26
正解ではないと思います。Private Bytesは、物理メモリだけでなく、プロセス実行可能ファイルが要求したメモリ(RAM)の量を示します。したがって、プライベートバイトを監視することで、メモリリークのほとんどのケースを確実に検査できます。:: VisualAllocを試して、大量のメモリをコミットします(1.5Gなど)。プライベートバイトがワーキングセットよりもはるかに大きいことがわかります。これは、「ワーキングセットがプライベートバイトとメモリマップファイルである」が正しくないことを証明します。
Jay Zhu

4
実際、書き込みの理解は「ワーキングセットはメモリ内のプライベートバイトとメモリマップファイルです」と理解しています。また、プライベートバイトをスワップアウトすることもできます。プライベートバイトは、マシンにある物理メモリよりも大きいことがわかります。
Jay Zhu、

2
@Aaronaught:信頼できるインジケーターとデバッグに適した最初のステートメントは混乱します。プライベートバイトは、アプリケーションのメモリ領域のリークの信頼できるインジケータです。これは、依存DLLで間接的である可能性がありますが、アプリケーションのメモリ空間でのリークです。デバッグに使用できない理由を説明できますか?アプリケーションプロセスの完全なメモリダンプから、このメモリを消費しているものがわかります。デバッグに使用できない理由がわかりません。あなたはいくつかの光を当てることができますか?
G33kKahuna 2012年

@ G33kKahuna:意味のある意味でメモリダンプがメモリを消費していることをどのように教えてくれるのか、私には明確ではありません。時間をかけて厳格に制御された状況でいくつかのダンプを取らない限り、どのモジュールが実際に時間をかけてメモリをリークしているか。より非効率的で信頼性の低いデバッグ戦略を想像するのは困難です。プロファイラーは最近どこにでもあります。1つ使用します。
アーロノート

1
フル!objsizeを実行します。これにより、即時ヒープ内の固定オブジェクトが表示されます。eeheap -gcを確認すると確認できます。これにより、ボリュームがスタックしている場所が表示されます。通常、上記のすべてのコマンドでヒントを使用できない場合、プライベートバイトはGCで収集されていないオブジェクトによって消費されます。次に、gchandlesまたはgcleaksに進みます。これらのコマンドは、マップできないタイプ/オブジェクトアドレスを通知する必要があります。ポインタはまだ残っていますが、オブジェクトはなくなっています。これは、リリースされていないイベントハンドラーのようなカテゴリの問題です。
G33kKahuna

10

メモリリークを特定するために、perfmon、タスクマネージャ、またはそのようなツールを使用しないでください。これらは傾向を特定するのに適していますが、それ以外の場合はそれほどではありません。それらが絶対的な用語で報告する数値は、あいまいで集計されているため、メモリリークの検出などの特定のタスクに役立ちません。

この質問への以前の回答は、さまざまなタイプが何であるかについての素晴らしい説明を与えました。

ツールの推奨事項について質問します。私はMemory Validatorをお勧めします。数十億のメモリ割り当てを行うアプリケーションを監視できます。

http://www.softwareverify.com/cpp/memory/index.html

免責事項:私はメモリ検証ツールを設計しました。


1
(Javaで)単純なクラスファイルを実行することもできませんか?何ができますか?
jn1kk

スティーブンとデビルはどういうわけか関連しているか、クローンさえされていると思います...:D;)
Robert Koritnik

@StephenKellett、体験版はありますか?
Pacerier、2015

@Pacerierリンクをクリックすると、ページ左側の購入オプションのすぐ上に、x86バージョンとx64バージョンの両方のトライアルがあります。
Bradley A. Tetreault 2015

10

perfmonカウンタの定義は最初から壊れており、何らかの理由で修正するのが難しいようです。

Windowsメモリ管理の優れた概要は、MSDN のビデオ「メモリ管理の謎」でご覧いただけます。これは、メモリリークの追跡に必要なトピック(例:ワーキングセット管理)をカバーしていますが、関連するトピックで十分に詳しく説明しています。


perfmonカウンタの説明に関する問題のヒントを与えるために、MSDNの「Private Bytes Performance Counter-Beware!」からのプライベートバイトに関する裏話を次に示します。

Q:プライベートバイトはプライベートバイトではありません。

A:常駐していない場合。

Private Bytesカウンターは、プロセスのコミット料金を報告します。つまり、スワップアウトされた場合にプライベートメモリの内容を保持するためにスワップファイルに割り当てられたスペースの量。注:コミットされていない予約済み状態の仮想メモリと混同する可能性があるため、「予約済み」という言葉は避けています。


MSDNの「パフォーマンスプランニング」から:

3.3プライベートバイト

3.3.1説明

プライベートメモリは、他のプロセスと共有できないプロセスに割り当てられたメモリとして定義されます。このメモリは、そのような複数のプロセスがマシンで実行される場合、共有メモリよりも高価です。(従来の)アンマネージdllのプライベートメモリは、通常C ++の静的要素で構成され、dllのワーキングセット全体の5%程度です。


1
それがどのように壊れているかについてのめちゃくちゃ良い例のために投票してください!
ブルーノブラント

最初の引用は間違っています。「プライベートバイト」を割り当てるには、「スワップファイルに割り当てる」必要はありません(実際にはページファイルと呼ばれます)。「プライベートバイト」を割り当てるためのページファイルも必要ありません。実際、プライベートバイトを割り当てて、すぐにはどこのスペース使用されず、割り当てられた量を使用しない場合があります。
Jamie Hanrahan

2番目の引用はあまり良くありません。DLLコードで使用されるプライベートバイトは、必ずしもDLL内で静的に割り当てられるとは限りません。DLLコードは、VirtualAlloc、HeapAlloc(mallocおよびCRTLの新機能)などを完全に自由に呼び出すことができます。また、プライベートメモリサイズをワーキングセットサイズのパーセンテージとして記述しようとしますが、これは無意味です。前者は仮想サイズであり(同じ入力でコードを使用してもすべて同じです)、後者は物理的です(メモリの量に応じて、実行ごとに根本​​的に異なる可能性があります-飢えたマシンです)。
ジェイミー・ハンラハン

5

ここに興味深い議論があります:http : //social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/307d658a-f677-40f2-bdef-e6352b0bfe9e/ このスレッドについての私の理解は、小さな割り当てを解放するとPrivate BytesまたはWorking Setには反映されません。

短い話:

私が電話したら

p=malloc(1000);
free(p);

次に、プライベートバイトは割り当てのみを反映し、割り当て解除は反映しません。

私が電話したら

p=malloc(>512k);
free(p);

その後、プライベートバイトは割り当てと割り当て解除を正しく反映します。


7
これは、C標準ライブラリのメモリ関数がカスタムまたはWin32ヒープを使用するという事実によって説明されます。これは、低レベルのプロセスレベルのメモリ管理に加えて、メモリ管理メカニズムです。
キベリアス2013年

@キベリアス、それでどうやってそれを下回るの
Pacerier 2015

while(1)free(malloc(1000)); //これによりPrivate Bytesが永久に増加しますか?
franckspike 2015

2
@franckspike:いいえ、CRTはOSから新しいページを要求する代わりに、以前に解放されたメモリを再利用するため、特定のポイント(通常は約4 kBですが、これは異なる場合があります)に増加して停止します。
ミラル2015

@Pacerier:VirtualAllocおよびVirtualFreeを呼び出すことができます。
Jamie Hanrahan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.