web-dev-qa-db-ja.com

bad_allocの原因を見つけるためのデバッグ戦略

私のプログラムにはかなり深刻なバグがあります-時々new()を呼び出すとbad_allocがスローされます。

Bad_allocで見つけたドキュメントから、次の理由でスローされているようです:

  1. コンピューターのメモリが不足すると(これは間違いなく発生していません。4GBのRAMがあり、5 MB未満(タスクマネージャーでチェック)を使用すると、プログラムはバックグラウンドで何も実行せずにbad_allocをスローします)。

  2. メモリが断片化されすぎて新しいブロックを割り当てることができない場合(これもありそうにありません-私が割り当てた最大サイズのブロックは約1KBであり、クラッシュが発生する前に100回を超えて実行されません)。

これらの説明に基づくと、bad_allocがスローされる可能性のある場所は本当にありません。

ただし、実行しているアプリケーションが複数のスレッドを実行しているため、問題の原因となっている可能性があります。すべてのオブジェクトを1つのスレッドでテストすることにより、すべてがスムーズに動作しているように見えます。ここで起こっていると考えることができる唯一の他のことは、同時に複数の場所でnew()を呼び出すことによって引き起こされるある種の競合状態である可能性がありますが、その動作を防ぐためにミューテックスを追加しようとしました無効。

プログラムは数百行あり、問題が実際にどこにあるのかわからないので、投稿するコードスニペットがあるかどうか、わかりません。代わりに、この種のことをテストするのに役立つツールがあるのか​​、この問題を解決するのに役立つ一般的な戦略があるのか​​と思いました。

私はMicrosoft Visual Studio 2008を使用しており、Pocoを使用してスレッド化しています。

37
Salami

別の考えられる問題は、プログラムが使用している容量が5MB未満であると述べている一方で、割り当てようとしているスペースの量については触れていないことです。割り当てサイズを決定するために使用する値を破壊するいくつかの競合状態があり、37TBまたはそのようなナンセンスを割り当てようとしている可能性があります。

特に可能性は低いと思いますが、確認する価値はあります。

22
Brooks Moses

bad_allocは、ヒープが割り当てに使用するメモリのプールを管理するためにヒープが使用するポインタを上書きするバグがある場合にもスローされます。

その最も一般的な原因は、割り当てられたメモリブロックの終わりを超えて(または開始前に書き込みを行うことですが、それほど一般的ではありません)。解放された後のメモリブロックへの書き込みはほとんど同じです。これはヒープの破損と呼ばれます。

また、Windowsの32ビットプロセスには最大2GBのアドレススペースがあります(大きなアドレスを認識するプログラムの場合は3GB)。これは、インストールされているRAM=メモリに関係なく、1GBのRAMしかなくても、アドレス空間が不足するまで割り当ては失敗しません。

これは、C++でのメモリ破損の良い議論です http://www.eventhelix.com/RealtimeMantra/Basics/debugging_software_crashes_2.htm

24
John Knoeller

いくつかの説明:

Windowsのすべてのプロセスは4GBの仮想メモリを取得します。そのうち2GBはユーザースペース用で、残りはカーネルスペース用です。 RAMの4GBは仮想メモリに貢献しませんが、物理メモリ用です。

2 GBのメモリでは、すべてのEXE、DLLが読み込まれ、メモリ割り当てに1.6〜1.7 GBはほとんど使用されません。このメモリでは、割り当て用の連続したメモリがない場合、メモリの割り当ては失敗します。

3
aJ.

bad_allocは他のコードからもスローされます。

STLコンテナーで使用するために設計された制限付きのメモリプールで使用されることを確認しました。サイズ制限に達すると、bad_allocがスローされ、ソフトウェアはそれを処理する必要がありました。

1
Zan Lynx

私は実際に前にこの問題を抱えていましたが、プロジェクトをクリーンアップして再構築することで修正されました。奇妙な振る舞いがあるときは常に試してみる価値があります(コンパイルに数時間かかる巨大なプロジェクトでない限り)。

1
Timmmm

これをデバッグする方法は、デバッガでキャッチポイントを設定することです。 gdbでは、プログラムが例外をスローするたびに停止するようデバッガーに要求するには、「catch throw」と言います。プログラムが通常のビジネスの過程で多くの例外をスローしてキャッチする場合は、std :: bad_allocのみをキャッチするようにそれを調整できます。デバッガーは、std :: bad_allocを生成する割り当て関数の内部で停止します。この場合、要求されたバイト数が期待したものではないことがすぐにわかります。

0
AndyJost