2016-12-06 14 views
0

オブジェクトが許可された仮想アドレス空間(Win32では2Gb)より多くのメモリを割り当てようとします。 std::bad_allocが捕捉され、オブジェクトが解放されます。プロセスのメモリ使用量が低下し、プロセスは続行されます。ただし、以降のメモリ割り当ては、別のstd::bad_allocで失敗します。 VMMapを使用してメモリ使用量を確認すると、ヒープメモリは解放されたように見えますが、実際には空き領域が残っていないためプライベートとしてマークされています。やりたいことは、終了して再開するようだ。私は断片化の問題を理解するだろうが、なぜ、プロセスがリリース後にメモリを戻すことができないのだろうか?オブジェクトが破棄されているにもかかわらずbad_allocをキャッチした後に「プライベートメモリ」が解放されない

オブジェクトは、QListQListです。アプリケーションはマルチスレッド化されています。私は小さな再生器を作ることができましたが、問題を1回だけ再現することができましたが、ほとんどの場合、再生されたメモリは解放されたメモリを再び使用できます。

Qtは何か卑劣なことをしていますか?それとも、それはリリースを遅らせるwin32ですか?

+0

win32「VirtualFree(p、0、MEM_RELEASE)」を呼び出すと、関数が返るときにメモリが解放されます( 'p'が正しい場合) - 100%' VirtualFree'呼び出されていないか、悪い引数で呼び出されました – RbMm

+0

** QListの 'QList'は何ですか?それはここで重要なことです。 QVariantの –

+0

これは基本的にスプレッドシートです。通常、文字列またはURLの形式で数値が含まれます。 – Narcolessico

答えて

1

Martin Drabの答えは私を正しい道に押し込んだ。

ここでの問題は、512K以上のブロックが VirtualAllocのを直接呼び出すしていることで、他のすべてがこれより小さいの を割り当てられている:私は何が起こっているかを明確にし、このold messageを発見したヒープ割り当てに関する調査ヒープセグメント。悪いニュースは、セグメントがされることはありません が(全体または一部)をリリースしそうなものは、あなたが問題K.

あなたは他のヒープまたはブロック512を超える のためにそれらを使用することはできません

を小さなブロックでアドレス全体 スペースを取るということですQt関連ではなくWindows関連です。私は最終的にchar配列の平文std::vectorでそれを再現できました。デフォルトのヒープ・アロケータは、コレスポンデント・アロケーションが明示的に解放された後でもアドレス空間セグメントを変更しません。この比率は、プロセスが同様のサイズのバッファを再度要求する可能性があり、ヒープマネージャは、古いアドレスセグメントを圧縮して新しいアドレスセグメントを作成する代わりに、既存のアドレスセグメントを再利用する時間を節約することです。

これは、使用可能な物理メモリと仮想メモリの量には関係ありません。これらのセグメントが空いているにもかかわらず、アドレス空間はセグメント化されたままであるのはのみです。これは、アドレス空間がわずか2Gb(3つあり得る)である32ビットアーキテクチャで深刻な問題である。

これは、メモリが解放された後であっても「プライベート」とマークされ、コミットされたメモリが非常に低いにもかかわらず平均サイズのmallocに対して同じプロセスで使用できないように見える理由です。

問題を再現するには、ちょうど512Kbより小さいチャンクのベクトルを作成します(新しいかmallocで割り当てる必要があります)。メモリがいっぱいになってから解放された後(制限に達しても例外が発生した場合でも、メモリにエラーがなくなった場合でも)、プロセスは512Kbを超える容量を割り当てることができません。メモリは無料で、同じプロセス(「プライベート」)に割り当てられていますが、すべてのバケットは小さすぎます。

ただし、ヒープセグメントの圧縮を強制する方法はありません。私はthisthisで試しましたが、運がありませんでした。 POSIX fork()herehereを参照)とまったく同じものはありません。唯一の解決策は、creating a private heapのような低レベルの処理を行い、小さな割り当て(上記のメッセージで示唆されているように)を破棄したり、カスタムアロケータを実装したりすることです。一番簡単な解決策は、プロセスを閉じて再起動することです。

1

私はあなたの問題を理解しているので、ある時点で失敗するヒープから大量のメモリを割り当てています。メモリをプロセスヒープに解放することは、ヒープマネージャがヒープのフリーブロックのみを含む仮想ページを実際に解放することを意味するものではありません(パフォーマンス上の理由により)。したがって、仮想メモリを直接割り当てようとすると(VirtualAllocまたはVirtualAllocEx)、ほとんどのメモリがヒープマネージャによって消費され、直接割り当ての試みを知る機会がないため、試行は失敗します。

これはおそらくあなたができることです。独自のヒープ(HeapCreate)を作成し、その最大サイズを制限することができます。このヒープを使用するようにQtを説得する必要があるので、かなり難しいかもしれません。

大量のメモリを割り当てる場合は、ヒープ関数ではなくVirtualAllocを使用することをお勧めします。要求されたサイズが512 KBを超える場合、ヒープ・マインジャーは実際にVirtualAllocを使用して要求を満たします。ただし、領域を解放するときにページを実際に解放するかどうか、または他のヒープ割り当て要求を満たすために領域を使用するかどうかはわかりません。

+0

"オブジェクトはQListsのQListです。"誰も手動WINAPI呼び出しを行っていません。 –

+0

次に、QListのソースを調べて、割り当ての失敗がどこで発生しているか、Qtがこのタイプの例外を正しく処理するかどうかを調べることをお勧めします。私は非常に多くのプログラマーがメモリ不足の例外のためにdo-not-care戦略を採用しているのを見ました。 Qtではどの戦略が使われているのか分かりません。 –

関連する問題