22

質問はそれをすべて言いますが、ここに例があります:

typedef struct mutable_t{
    int count, max;
    void **data;
} mutable_t;


void pushMutable(mutable_t *m, void *object)
{
    if(m->count == m->max){
        m->max *= 2;
        m->data = realloc(m->data, m->max * sizeof(void*));
    }
    // how to handle oom??
    m->data[m->count++] = object;
}

すべてのデータをNULLにするのではなく、メモリ不足を処理するにはどうすればよいですか?

編集-実行できることがあると仮定しましょう。たとえば、どこかでメモリを解放するか、少なくともユーザーに「それはできません。メモリが不足しています」と伝えます。理想的には、そこに割り当てられたものを残したいと思います。

4

8 に答える 8

28

標準的な手法は、reallocからの戻り値を保持するための新しい変数を導入することです。次に、成功した場合にのみ入力変数を上書きします。

tmp = realloc(orig, newsize);
if (tmp == NULL)
{
    // could not realloc, but orig still valid
}
else
{
    orig = tmp;
}
于 2009-12-31T18:36:37.667 に答える
9

失敗したときに何をするかについての戦略はrealloc()、アプリケーションによって異なります。質問は一般的すぎて、考えられるすべてのケースに答えることができません。

その他の注意事項:

決してしません:

a = realloc(a, size);

realloc()失敗すると、元のポインタが失われ、realloc()元のfree()メモリが失われるため、メモリリークが発生します。代わりに、次のようにします。

tmp = realloc(a, size);
if (tmp)
    a = tmp;
else
    /* handle error */

私が言いたい2番目のポイントはマイナーであり、それほど重要ではないかもしれませんが、とにかくそれについて知っておくのは良いことです。ファクターによって割り当てられるメモリを増やすことfは良いことです。malloc() 最初にnバイトだとしましょう。次に、より多くのメモリが必要になるためrealloc()、サイズはn×fになります。次に、より多くのメモリが必要になるため、 n × f2バイトが必要です。realloc()前の2つのメモリブロックのスペースを使用する場合は、n × f2≤n+n×fあることを確認する必要があります。この方程式を解くと、f≤(sqrt(5)+1)/ 2 = 1.618黄金比)が得られます。1.5私はほとんどの場合、係数を使用します。

于 2009-12-31T20:08:53.690 に答える
9

これは、このテーマについて本質的に2つの考え方があるため、ちょっとしたホットボタンのトピックです。

  1. OOMを検出し、関数にエラーコードを返すようにします。
  2. OOMを検出し、プロセスをできるだけ早くクラッシュさせます

個人的に私はキャンプ#2にいます。非常に特殊なタイプのアプリケーションを期待してください。OOMは致命的な期間です。真の、完全に記述されたコードはOOMを処理できますが、メモリがない場合でも安全なコードの記述方法を理解している人はほとんどいません。努力する価値がほとんどないため、実際にそれを行うのに煩わされることはさらに少なくなります。

エラーコードをOOMの呼び出し関数に渡すのは嫌いです。これは、呼び出し元に「失敗し、それについて何もできない」と伝えるのと同じだからです。代わりに、結果のダンプが可能な限り有益になるように、高速でクラッシュすることを好みます。

于 2009-12-31T18:30:21.843 に答える
3

作業するときに従うべき最初のルールは、に渡したのと同じポインタにreallocの戻り値を割り当てないことです。reallocこれ

m->data = realloc(m->data, m->max * sizeof(void*)); 

悪い。失敗した場合realloc、nullポインタを返しますが、古いメモリの割り当てを解除しません。上記のコードはnullになりますm->dataが、以前にポイントされていた古いメモリブロックは、m->dataメモリリークになる可能性があります(他に参照がない場合)。

の戻り値はrealloc、最初に別のポインタに格納する必要があります

void **new_data;
...
new_data = realloc(m->data, m->max * sizeof(void*)); 

m->data次に、成功/失敗を確認し、成功した場合はの値を変更できます

if (new_data != NULL)
  m->data = new_data;
else
  /* whatever */;
于 2009-12-31T18:42:10.650 に答える
2

それは完全にあなたの問題です!ここにいくつかの基準があります:

  • あなたは理由でその記憶を求めました。それが利用できない場合、あなたのプログラムの仕事は運命づけられていますか、それとも何かを続けることができますか?前者の場合、エラーメッセージでプログラムを終了します。それ以外の場合は、エラーメッセージを表示して続行できます。

  • 時間と空間のトレードオフの可能性はありますか?より少ないメモリを使用するアルゴリズムを使用して試行した操作に応答できますか?これは大変な作業のように聞こえますが、実際には、最初は十分なメモリがないにもかかわらず、プログラムの操作を続行できる可能性があります。

  • あなたのプログラムがこのデータと十分なメモリなしで足を引きずり続けるのは間違っているでしょうか?その場合は、エラーメッセージで終了する必要があります。誤ったデータの処理をやみくもに続けるよりも、プログラムを強制終了する方がはるかに優れています。

于 2009-12-31T18:32:01.890 に答える
2
  1. アプリケーションフレームワークがOOMを処理する方法をご覧ください。多くは単にOOMを処理しません。ほとんどの場合、フレームワークは、どこかで非常に明確かつ明確に言われない限り、RAMがフリーでない状態では適切に動作しません。フレームワークがOOMを処理せず、マルチスレッド化されている場合(多くは最近です)、多くの場合、OOMはプロセスのショーの終わりになります。マルチスレッド化されていなくても、崩壊に近い可能性があります。プロセスを終了するかフレームワークを終了するかは、論点になる可能性があります。予測可能な即時終了は、近い将来のある半ランダムなポイントでのクラッシュよりも少し良いかもしれません。

  2. OOMによるメモリ使用のみが制限されている(つまり、現在の操作がロールバックされるか、クリーンに中止される)明確に定義された一連の操作に別の専用サブメモリプール(つまり、通常のmallocではない)を使用している場合プロセス全体やメインメモリプールではなく、サブメモリプールのOOM)、およびそのサブプールがアプリケーションフレームワークでも使用されていない場合、またはフレームワークとアプリケーションの残りの部分全体が意味のあるものを維持するように設計されている場合ノーフリーRAM状態(カーネルモードや一部のタイプのシステムプログラミングではまれですが、前代未聞ではありません)での状態と継続的な動作は、プロセスをクラッシュさせるのではなく、エラーコードを返すのが正しい場合があります。

  3. 理想的にはメモリ割り当ての大部分(またはさらに理想的にはすべて処理の一部の割り当て)は、データの整合性の損失や失敗した場合に必要なロールバックコーディングの量の問題を最小限に抑えるために、処理のできるだけ早い段階で、理想的には適切に開始する前に割り当てる必要があります。実際には、プログラミングのコストとプロジェクトの時間を節約し、データの整合性を維持するために、アプリケーションはデータベーストランザクションに依存し、ユーザー/サポート担当者がGUIのクラッシュ(またはサーバーのクラッシュ)を検出して、外出時にアプリを再起動する必要があります。可能な限り最善の方法で何千もの潜在的なOOM状況に対処してロールバックするために書き込まれるのではなく、メモリエラーが発生します。次に、アプリが過負荷状態にさらされるのを制限することに重点を置きます。これには、追加の検証、データサイズの制限、同時接続とクエリが含まれる場合があります。

  4. 使用可能として報告されているメモリの量を確認した場合でも、他のコードがメモリを割り当てたり解放したりして、メモリチェックの基準を変更し、OOMにつながる可能性があります。したがって、割り当てる前に使用可能な空きRAMを確認することは、アプリケーションが使用可能なRAM制限内で動作し、ユーザーを満足させるのに十分な時間データの整合性を維持することを確認するという問題に対する信頼できる解決策ではないことがよくあります。

  5. 最適な状況は、フレームワークのオーバーヘッドを含め、考えられるすべてのケースでアプリが必要とするメモリの量を把握し、その数値をアプリケーションで使用可能なRAMの量の範囲内に保つことですが、システムは多くの場合、外部の依存関係によって非常に複雑になります。データサイズなので、これを達成するのは非現実的です。

もちろん、酸テストは、高い稼働時間と、まれなデータの破損、損失、またはクラッシュによって、ユーザーを十分に満足させることです。場合によっては、クラッシュした場合に再起動するためのモニタープロセスを備えたアプリが便利です。

reallocに関して:

reallocからの戻り値を確認します-一時変数に入れます。要求された新しいサイズが>0の場合にのみ、NULLであるかどうかに注意してください。それ以外の場合は、非一時変数に配置します。

例えば

    void* temp = realloc(m->data, m->max * sizeof(void*));
    if (m->max!=0&&temp==NULL) { /* crash or return error */ }
    m->data =(void**)temp;

編集

(1)の「ほとんどの場合」を「多くの場合」に変更しました。

メモリーが割り当てられない場合は「何かできる」とおっしゃっていたと思います。しかし、メモリ管理は非常にグローバルな考慮事項です(!)。

于 2009-12-31T19:29:45.223 に答える
1

reallocから発生する可能性のある別の微妙なエラーもあります。返されたNULLポインタから発生するメモリリークはかなりよく知られています(ただし、遭遇することは非常にまれです)。プログラムで、realloc呼び出しが原因でクラッシュが発生することがありました。これに似たreallocを使用して、サイズを自動的に調整する動的構造がありました。

m->data = realloc(m->data, m->max * sizeof(void*)); 

私が犯したエラーは、m-> max == 0をチェックしないことでした。これにより、メモリ領域が解放されました。そして、私のm->dataポインタから古いものを作成しました。

私はそれが少し話題から外れていることを知っていますが、これは私がこれまでreallocで抱えていた唯一の本当の問題でした。

于 2009-12-31T18:51:25.050 に答える
1

問題が発生しました。構成はOS:win7(64); IDE:vs2013; Debug(Win32)です。
メモリが入っているためにreallocがnullを返したとき、2つの解決策があります。

1.プロジェクトのプロパティを変更して、LARGEADDRESSESを有効にします。
2.ソリューションプラットフォームをWin32からx64に変更します。

于 2016-02-26T04:41:23.367 に答える