C コードで OOM (メモリ不足) エラーを検出する必要がありますか?

ユーザーまたはシステム管理者がプロセスのメモリ領域を制限 (ulimit を参照) したり、オペレーティング システムがユーザーごとのメモリ割り当て制限をサポートしている場合は、多くのメモリを搭載した最新のコンピューターでもメモリ不足の状態が発生する可能性があります。病理学的なケースでは、断片化により、これがかなり可能性が高くなります。

ただし、最近のプログラムでは動的に割り当てられたメモリの使用が一般的であるため、正当な理由から、メモリ不足エラーの処理が非常に困難になります。この種のエラーのチェックと処理は、あらゆる場所で実行する必要があり、複雑さが高くなります。

いつでもクラッシュできるようにプログラムを設計する方がよいと思います。たとえば、ユーザーが明示的に保存しない場合でも、ユーザーが作成したデータが常にディスクに保存されるようにします。 (たとえば、vi -r を参照してください。) このようにして、エラーが発生した場合にプログラムを終了するメモリを割り当てる関数を作成できます。アプリケーションはいつでもクラッシュを処理できるように設計されているため、クラッシュしても問題ありません。ユーザーは驚くでしょうが、(多くの) 作業を失うことはありません。

決して失敗しない割り当て関数は、次のようなものです (デモンストレーションのみを目的とした、テストもコンパイルもされていないコード):

/* Callback function so application can do some emergency saving if it wants to. */
static void (*safe_malloc_callback)(int error_number, size_t requested);

void safe_malloc_set_callback(void (*callback)(int, size_t))
{
    safe_malloc_callback = callback;
}

void *safe_malloc(size_t n)
{
    void *p;

    if (n == 0)
        n = 1; /* malloc(0) is not well defined. */
    p = malloc(n);
    if (p == NULL) {
        if (safe_malloc_callback)
            safe_malloc_callback(errno, n);
        exit(EXIT_FAILURE);
    }
    return p;
}

Valerie Aurora の記事 Crash-only software は参考になるかもしれません。


質問の反対側を見てください:メモリを malloc すると失敗し、しない するとき、mallocでそれを検出します

明らかに、ポインターを逆参照しようとするとき。

どのように検出しますか? Bus error を取得することによって コア ダンプとデバッガーで追跡する必要がある malloc の後のどこかに似たようなものです。

一方、あなたは書くことができます

  #define OOM 42 /* just some number */

  /* ... */

  if((ptr=malloc(size))==NULL){
      /* a well-behaved fprintf should NOT malloc, so it can be used
       * in this sort of context
       */
      fprintf(stderr,"OOM at %s: %s\n", __FILE__, __LINE__);
      exit(OOM);
   }

"OOM at parser.c:447" を取得します。

あなたが選んでください。

更新

グレースフル リターンについての良い質問です。正常な復帰を保証することの難しさは、一般に、特に C では、それを行う方法のパラダイムやパターンを実際に設定できないことです。C は結局のところ、派手なアセンブリ言語です。ガベージ コレクション環境では、GC を強制できます。例外のある言語では、例外をスローして物事を巻き戻すことができます。 C では自分で行う必要があるため、どれだけの労力を費やすかを決める必要があります。

ほとんどの プログラム、異常終了はあなたができる最善のことです。このスキームでは、(願わくは) stderr で有用なメッセージを取得します。もちろん、ロガーなどへのメッセージである可能性もありますが、戻りコードとして既知の値が返されます。

回復時間が短い信頼性の高いプログラムでは、システムを存続可能な状態に戻そうとするコードを作成する回復ブロックのような状態に陥ります。これらは優れていますが、複雑です。私がリンクした論文は、それらについて詳しく述べています.

途中で、動的メモリの独自のプールを管理するなど、より複雑なメモリ管理スキームを考え出すことができます。

しかし、十分にクリーンアップするための一般的なパターンはありません (とにかく私は知っています)。 確実に戻り、周囲のプログラムを続行できるようにします。


プラットフォームに関係なく (おそらく組み込みシステムを除く)、NULL を確認することをお勧めします。 そして、手動でクリーンアップを一切 (または多く) せずに終了します。

メモリ不足は単純なエラーではありません。今日のシステムでは大惨事です。

The Practice of Programming (ブライアン W. カーニハンとロブ パイク、1999 年) は emalloc() のような関数を定義しています。 メモリが残っていない場合、エラー メッセージを表示して終了します。