3

私はネイティブ C++ アプリケーションを持っており、長期間にわたって多くのことを追跡する必要があります。プロセスが 800 ~ 1200 MB のメモリに達しているとタスク マネージャが示している場合、制限は約 2 GBであるはずですが、メモリが不足しています。

プロセスに対して VMMap を実行したときに何が起こっているのか、ようやく手がかりが得られましたが、それだけでさらに疑問が生じました。私が発見したこと:

  • 合計サイズ (タイプ: 合計、列: サイズ) は、タスク マネージャー/プロセス エクスプローラーが報告していたものよりもはるかに大きい
  • 合計サイズは、実際には、プログラムがメモリ不足になる前に 2GB を超えることはできない値のようです
  • メモリ使用量の不一致は、ほぼ完全に「プライベート データ」が原因です。「コミット」よりも「サイズ」の方がはるかに多くなります。約 800MB のプライベート データがコミットされているケースを見てきましたが、「サイズ」は約 1700MB です。
  • 「プライベート データ」の最大のブロックは、主に、「読み取り/書き込み」保護があり、完全にコミットされている 1 つの小さなサブブロック (通常は 4K から 16K の間) と、1 つの大きなサブブロック (4K から 16K の間) のペアのパターンで構成されます。 90K および 400K) には、「予約済み」保護があり、コミットされていません。これは、リソースの膨大な浪費のように思えます。そして、通常、最後に「予約済み」でコミットされていない1つの大きな(数メガバイトの)サブブロックがあります。
  • ペアの小さな部分には通常、私が認識できる文字列がありますが、大きなブロックには文字列がまったくありません。

これらのサブブロック ペアの例: (私のアプリケーションではありませんが、考え方は同じです) http://www.flickr.com/photos/95123032@N00/5280550393

プライベート データの 1 つのブロックが完全にコミットされると、新しいブロック (通常、以前の最大のブロックと同じか 2 倍のサイズ) が割り当てられるように見えます。公正に聞こえます。ただし、3 つのブロックがあり、それぞれが 100MB を超えており、コミットされているのは 30MB 未満です。私のアプリケーションは、それが可能なような方法で動作するべきではありません (つまり、400MB を使い切ってから、数時間のうちに 300MB 縮小します)。

私が知る限り、「サイズ」は割り当てられた仮想メモリアドレス空間の実際の量です。「コミット済み」は、実際に使用されている「サイズ」の量です (つまり、new/malloc の呼び出しによって)。それが本当なら、なぜサイズとコミット済みの間にこれほど大きな違いがあるのでしょうか? また、サイズが数百メガバイトのブロックを割り当てているのはなぜですか?

少し奇妙な点は、Windows 7 で実行すると動作がまったく異なることです。2003 Server では、アプリケーションはプライベート データを使用しますが、Windows 7 では、アプリケーションはヒープを使用します。なぜ?VMMap が 2003 では主にプライベート データの使用量を示しているのに、7 では主にヒープの使用量を示しているのはなぜですか? 違いは何ですか?違いの 1 つは、VMMap の [ヒープ割り当て...] ボタンを使用して、すべてのプライベート データがどこに割り当てられているかを確認できないことです。

std::string の過度の使用がこの問題を引き起こしているのではないかと考え始めていました。なぜなら、ペアで認識した文字列 (上記) は主に std::string に格納された文字列で構成されており、頻繁に作成および破棄されていたからです (多くのことを意味します)。メモリの割り当て/割り当て解除)。文字配列を使用するか、メモリ プールのメモリを使用するようにできる限り変換しましたが、効果がないようです。頻繁に新規作成/削除される他のすべてのオブジェクトには、すでに独自のメモリ プールがあります。

断片化ヒープが少ないこともわかったので、それを有効にしてみましたが、やはり違いはありませんでした。Windows 2003 が実際には適切なヒープを使用していないためだと思います。VMMap は、低断片化ヒープが有効になっていることを示していますが、実際には使用されていないため (つまり、代わりにプライベート データを使用しているため)、実際には違いはありません。

実際に起こっているように見えるのは、これらのサブブロックのペアが大きなプライベート データ ブロックを断片化し、OS が新しいブロックを割り当てていることです。最終的に、断片化がひどくなり、コミットされていない領域がたくさんあるにもかかわらず、どれも使用できないように見え、プロセスがメモリ不足になります。

だから私の質問は:

  1. Windows Server 2003 がヒープではなくプライベート データを使用するのはなぜですか? それは問題ですか?Windows Server 2003 で代わりにヒープ メモリを使用する方法はありますか? もしそうなら、それは私の状況をまったく改善しますか?
  2. OS のメモリ アロケータによってプライベート データがどのように割り当てられるかを制御する方法はありますか?
  3. 独自のカスタム ヒープを作成して (コードベースの大部分を変更せずに) 割り当てることは可能ですか? カスタム ヒープを作成できることはわかっていますが、私が知る限り、通常どおり new を呼び出したり、STL コンテナーを使用したりするのではなく、カスタム ヒープから明示的に割り当てる必要があります。
  4. 私が見逃しているもの、または試してみる価値のあるものはありますか?
4

3 に答える 3

3

プライベート データは、2 つ以上のプロセス間で共有されていないすべてのメモリの単なる分類です。ヒープ、再配置された dll ページ、プロセス内のすべてのスレッドのスタック、共有されていないメモリ マップ ファイルなどは、プライベート データのカテゴリに分類されます。

プロセスからの (VirtualAlloc 経由の) メモリ要求は、条件の 1 つが真の場合、OS によって失敗します。

  1. 要求されたサイズを保持するための連続した仮想アドレス空間 (メモリではない) が利用できません。
  2. コミット チャージ (すべてのプロセスとオペレーティング システムの合計メモリ コミット メモリ) が上限 (RAM + ページ ファイル サイズ) に達しました。

これとは別に、ヒープの割り当ては、拡張中に、拡張をトリガーした割り当て要求のサイズよりも多くのメモリを実際に取得しようとするなど、独自の理由で失敗する可能性があります。それが失敗した場合、実際に要求されたサイズはVirtualAlloc を通じて利用できます。

メモリを蓄積する傾向があるいくつかのものは、

  1. 多くのヒープを持つと、より多くのメモリを確保できるため、メモリを占有します。多くのヒープは、多くの予約済みスペースがおそらく未使用になることを意味します。ヒープ圧縮が役立つ場合があります。
  2. vector や map などの STL コンテナーは、要素が削除された後に縮小されない場合があります。それらを圧縮することも役立つかもしれません。
  3. COM のようなライブラリはキャッシュを行うため、メモリを蓄積します。個々のライブラリを調査して、メモリを大量に消費する傾向を把握するのに役立つ場合があります。
于 2013-03-29T19:27:17.963 に答える
0

同じ問題が発生しています。

Windows 2003 で、gcnew を使用して 22MB の配列を割り当てようとすると、C++/CLI モジュールでメモリ不足の例外が発生します。Windows 7 でも同じプロセスで問題なく動作します。

VMMap は、「プライベート データ」エントリが win2003 でほぼ 2 GB であることを示しています。/3GB フラグを有効にした後、このエントリもほぼ 3GB に増加しました。「ヒープ」エントリは約 14 MB で、「マネージド ヒープ」は何もありません。

Windows 7 では、「プライベート データ」はわずか 62 MB、「ヒープ」は 316 MB、「マネージド ヒープ」は 397 MB です。全体のメモリ使用量は、win2003 よりもはるかに少なくなっています。

于 2013-12-03T10:06:34.077 に答える
0

タスク マネージャーが、プロセスが 800 ~ 1200 MB のメモリに達したことを示している場合、制限は約 2 GB である必要があります。

2GB の制限が仮想メモリにあるのに、タスク マネージャーで「ワーキング セット」を見ていると思われます。タスク マネージャーには、予約されている VM の量は表示されません。コミットされた金額が表示されます。

「コミット済み」は、実際に使用されている「サイズ」の量です (つまり、new/malloc の呼び出しによって)。

いいえ、コミット済みとは、実際にページにアクセスしたことを意味します (つまり、アドレスに移動して、ロードまたはストア操作を行いました)。

1. Windows Server 2003 がヒープではなくプライベート データを使用するのはなぜですか?

Mark Russinovich と Aaron Margosis による「Windows Sysinternals Administrator's Reference」によると:

プライベート データ メモリは、VirtualAlloc によって割り当てられ、ヒープ マネージャまたは .Net ランタイムによってさらに処理されないメモリです。

したがって、プログラムが 2 つの OS でメモリを異なる方法で管理しているか、Windows Server 2003 でこのメモリがヒープとして管理されている方法を VMmap が検出できません。

4. 足りないものや試してみる価値のあるものはありますか?

32 ビット OS では 3 GB の制限で実行でき、64 ビット OS では 32 ビット プロセスに対して 4 GB の制限で実行できます。"/3G" と "/4G" は Google で検索してください。

この種のものに関する優れた情報源は、Mark Russinovich、David Solomon、および Alex Ionescu による書籍「Windows Internals 6th Edition」です。

于 2013-08-20T12:19:45.043 に答える