8

私は現在、Windows MSVC++ (9.0) アプリ用の例外ベースのエラー報告システム (つまり、例外構造と型/継承、コール スタック、エラー報告とログ記録など) に取り組んでいます。

私の質問は次のとおりです。メモリ不足エラーを正しく報告してログに記録する方法は?

このエラーが発生した場合、たとえばopbad_allocによってスローされたnew場合、多くの「機能」が利用できない可能性があり、主に追加のメモリ割り当てに関するものです。通常、lib で例外がスローされた場合はアプリケーションに例外を渡し、メッセージ ボックスとエラー ログ ファイルを使用して報告し、ログに記録します。もう 1 つの方法 (主にサービス用) は、Windows イベント ログを使用することです。
私が抱えている主な問題は、エラーメッセージを組み立てることです。 エラー情報を提供するために、静的なエラー メッセージ (文字列リテラル、メッセージ ファイルのエントリ、FormatMessage の使用) を定義し、コール スタックなどのランタイム情報を含めたいと思います。
この用途に必要な関数/メソッド

  • STL ( std::string, std::stringstream, std::ofstream)
  • ブラウン管 ( swprintf_s, fwrite)
  • または Win32 API ( StackWalk64, MessageBox, FormatMessage, ReportEvent, WriteFile)

MSDN で文書化されている以外に、Windows では多かれ少なかれ (Win32) または少なめ (STL) のクローズド ソースであるため、メモリ不足の問題でそれらがどのように動作するかはよくわかりません。

問題がある可能性があることを証明するために、bad_alloc を引き起こす簡単な小さなアプリを作成しました。

int main()
{
    InitErrorReporter();  

    try
    {
        for(int i = 0; i < 0xFFFFFFFF; i++)
        {
            for(int j = 0; j < 0xFFFFFFFF; j++)
            {
                char* p = new char;
            }
        }
    }catch(bad_alloc& e_b)
    {
        ReportError(e_b);
    }

    DeinitErrorReporter();

    return 0;
}

デバッガーを接続せずに 2 つのインスタンスを実行しましたが (リリース構成、VS 2008)、「何も起こりませんでした」。つまり、エラー レポートで内部的に使用した ReportEvent または WriteFile からのエラー コードはありませんでした。次に、デバッガーを使用してインスタンスを 1 つ、デバッガーを使用せずにインスタンスを 1 つ起動し、ReportError 行のブレークポイントを使用して、エラーを次々に報告しようとします。これは、デバッガーが接続されたインスタンスで正常に機能しました (問題のない LocalAlloc を使用しても、正しく報告され、エラーがログに記録されました)! しかし、タスクマンは、アプリが終了する前に大量のメモリが解放されるという奇妙な動作を示しました。例外がスローされたときだと思います。


複数のプロセス [編集] と複数のスレッド [/編集] が多くのメモリを消費している可能性があることを考慮してください。そのため、事前に割り当てられたヒープ領域を解放することは、報告したいプロセスのメモリ不足環境を回避するための安全な解決策ではありません。エラー。

前もって感謝します!

4

4 に答える 4

3

「事前に割り当てられたヒープ領域を解放しています...」. これはまさにあなたの質問を読んで思ったことです。しかし、私はあなたがそれを試すことができると思います。すべてのプロセスには、独自の仮想メモリ空​​間があります。別のプロセスが大量のメモリを消費するため、コンピューター全体が動作している場合でも、これは機能する可能性があります。

于 2010-08-20T17:53:41.307 に答える
2
  • 必要なバッファを事前に割り当てます
  • 静的にリンクし、CreateThread の代わりに _beginthreadex を使用します (そうしないと、CRT 関数が失敗する可能性があります) -- または -- 文字列 concat / i2a を自分で実装します
  • MessageBox (MB_SYSTEMMODAL | MB_OK) を使用する MSDN では、OOM 状態を報告するためにこれについて言及しています (一部の MS ブロガーは、この動作を意図したものとして説明しています: メッセージ ボックスはメモリを割り当てません)。

ロギングは難しく、少なくとも、ログ ファイルは既に開いている必要があります。

バッファリングの試みを避けるために、おそらく とFILE_FLAG_NO_BUFFERINGを使用するのが最適です。FILE_FLAG_WRITE_THROUGH最初のものは、書き込みとメモリ バッファーがセクター アライメントされている必要があります (つまり、GetDiskFreeSpace をクエリし、それによってバッファーをアライメントし、"セクター サイズの倍数" のファイル オフセットと、セクター サイズの倍数であるブロックにのみ書き込む必要があります。これが必要かどうか、または役立つかどうかはわかりませんが、すべての割り当てが失敗するシステム全体の OOM をシミュレートするのは困難です。

于 2010-08-23T19:24:37.273 に答える
1

複数のプロセスが多くのメモリを消費している可能性があることを考慮してください。そのため、事前に割り当てられたヒープ領域を解放することは、エラーを報告したいプロセスのメモリ不足環境を回避するための安全な解決策ではありません。

Windows (およびその他の最新のオペレーティング システム) では、各プロセスは、実行中の他のすべてのプロセスとは別の独自のアドレス空間 (別名メモリ) を持っています。そして、そのすべてがマシンの文字通りの RAM とは別のものです。オペレーティング システムは、物理 RAM から離れたプロセス アドレス空間を仮想化しています。

これは、Windows がプロセスによって使用されたメモリをハード ディスク上のページ ファイルにプッシュできる方法であり、それらのプロセスは何が起こったのかを知る必要がありません。

これは、1 つのプロセスがマシンの物理 RAM よりも多くのメモリを割り当てても実行できる方法でもあります。たとえば、512MB の RAM を搭載したマシンで実行されているプログラムは、1GB のメモリを割り当てることができます。Windows は、そのすべてを同時に RAM に保持することはできず、その一部はページ ファイルに保存されます。しかし、プログラムは知りません。

したがって、1 つのプロセスがメモリを割り当てても、別のプロセスが使用するメモリが少なくなることはありません。各プロセスは別々です。

各プロセスは、それ自体についてのみ心配する必要があります。したがって、事前に割り当てられたメモリのチャンクを解放するというアイデアは、実際には非常に実行可能です。

于 2010-08-20T18:26:10.737 に答える
0

説明したように、メモリが必要になる可能性があるため、CRT または MessageBox 関数を使用して OOM を処理することはできません。本当に安全にできる唯一の方法は、起動時にメモリのチャンクを割り当て、情報を書き込んでファイルまたはパイプへのハンドルを開き、OOM アウト時に WriteFile をそれに割り当てることです。

于 2010-08-20T23:25:49.040 に答える