私はネイティブ 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 が新しいブロックを割り当てていることです。最終的に、断片化がひどくなり、コミットされていない領域がたくさんあるにもかかわらず、どれも使用できないように見え、プロセスがメモリ不足になります。
だから私の質問は:
- Windows Server 2003 がヒープではなくプライベート データを使用するのはなぜですか? それは問題ですか?Windows Server 2003 で代わりにヒープ メモリを使用する方法はありますか? もしそうなら、それは私の状況をまったく改善しますか?
- OS のメモリ アロケータによってプライベート データがどのように割り当てられるかを制御する方法はありますか?
- 独自のカスタム ヒープを作成して (コードベースの大部分を変更せずに) 割り当てることは可能ですか? カスタム ヒープを作成できることはわかっていますが、私が知る限り、通常どおり new を呼び出したり、STL コンテナーを使用したりするのではなく、カスタム ヒープから明示的に割り当てる必要があります。
- 私が見逃しているもの、または試してみる価値のあるものはありますか?