ここには洗練されたものがあります。メモリの一部を少し切り取り、人里離れた場所に隠します...そして、オペレーティングシステム
記憶を
少しの背景
当番では、大きなメモリバッファーで多くの作業を行う必要があります(5000x40000ピクセルのイメージを想像してください)。 時々(断片化のため)、すべてに連続したメモリを割り当てることができない場合があります。 したがって、特定のメモリマネージャが記述され、そのメモリマネージャは、いくつかの部分に分けて割り当てられます。 当然、メモリマネージャは割り当てと削除の両方を行う必要があります。 その後、次の興味深いことが発見されました。リリース後のタスクマネージャーには、ブロック割り当て前と同じメモリ使用量のレベルが表示されます。 ただし、プログラム内の新しいメモリブロックを割り当てることはできません。 仮想メモリ分析ツール(Mark RusinovichのVMMap)を使用すると、コードの解放やTMの読み取りにもかかわらずメモリがビジーのままであることがわかります。
分析
メモリを割り当てて解放するプログラムをすばやく作成しましょう。 「Hello、World!」に似たそのようなもの:
int main(void) { const int blockCount = 1024; const int blockSize = 1024*1024; char **buf; printf("Hit something...\n"); getchar(); buf = (char**)malloc(blockCount*sizeof(char*)); for (int i=0; i<blockCount; i++) { buf[i] = (char*)malloc(blockSize*sizeof(char)); } printf("Memory allocated\n"); printf("Hit something...\n"); getchar(); for (int i=0; i<blockCount; i++) { free(buf[i]); } free(buf); printf("Hit something...\n"); printf("Memory freed\n"); getchar(); return 0; }
簡単な計算で、プログラムが1 GBのメモリを割り当て、すべてを解放する必要があることを確認できます。 開始して確認した後、すべてのメモリが解放されます。 うーん、システムは恐mailしているようです。 ただし、大きな部分をカットします。
次に、ソースコードを取得して少し修正します。
const int blockSize = 520133 // ...;
この場合、メモリは割り当てられたが解放されていないことがわかります。
「メモリ解放」の前:
「メモリ解放」後:
プログラマーの探究心はそこで止まりませんでした! 私はそのような効果が生じる閾値を探し始めました。 短いバイナリ選択の後、サイズが
- 520168バイト以上-リリースは問題ありません
- 520167バイト以下-説明されている問題があります
今後、このしきい値を説明することはできなかったと言います。
可能な説明
Googleを長時間監視し、フォーラムを検討した後、次の結論に達しました。
小さなチャンクが割り当てられた場合にmalloc / new関数を使用してメモリを割り当てた後、メモリはfree / delete関数によって解放されず、コミットされたビットから予約されたビットに渡されます。 そして、削除した直後に(明らかに1つのヒープのフレームワーク内で)このメモリにアクセスすると、再割り当てできます。 ただし、別のクラス(または静的関数)からメモリを割り当てようとすると、例外が発生します-メモリが足りません。 どうやら、静的関数からメモリを割り当てるとき、メモリはアプリケーションクラス内からの通常の割り当てと同じヒープに割り当てられません。
その結果、(小さな断片から)メモリの大きなブロックを作成した後、メモリが不足し、少し
間違った決定
VirtualAlloc / VirtualFree( MSDN )関数を使用するとこの問題が解決され、使用後にメモリがプロセスに完全に返されます(MEM_RELEASEキー)が、VirtualAllocを使用するとメモリの強力な断片化が発生し、約800 MBのメモリが使用できなくなります 最大空きブロックサイズは28Kbです。 この点では、従来のmallocは次のように機能します。 デフラグツールがあります。
最終決定
サードパーティのmallocとfreeの実装を見つけました(これは、狭い円で広く知られています)。これには、メモリの最適化という古典的な欠点がありますが、使用後にメモリを完全に解放します。 さらに、はるかに高速に動作します。
好奇心と渇きのためにリンクがあります
備考
OS * NIX(Ubuntu、Debian、CentOS)では、問題を再現できませんでした)
Windowsでは、問題はWindows Server 2003 x64、Windows 7 x64、Windows XP x32で再現されました。
長い間テストされた機能をすぐに直接信頼しないでください。キャッチすることができます。
UPD:MS VS 2010はWindowsでのコンパイルに使用されます