2

割り当てられたメモリをCで処理するためのクリーンな方法を考え出すのに苦労しています。次のようなものがあるとします。

void function(int arg) {
  char *foo;
  foo = (char *)malloc(sizeof(char) * 100);
  int i = func1(arg, &foo);

  char *bar;
  bar = (char *)malloc(sizeof(char) * 100);
  int j = func2(&bar);

  free(foo);
  free(bar);
}

私の問題はそれfunc1であり、func2エラーが発生する可能性がexit(1)あるので、解放する必要がfooありbarます。

エラーが発生した場合func1は、電話するだけでfree(foo)問題ありません。しかし、エラーが発生した場合は、解放する必要があるため、func2電話をかけることはできません。これは非常に複雑になる可能性があり、これはメモリを処理する正しい方法ではないと感じています。free(bar)foo

ここに何か足りないものがありますか?誰かが私に正しい方向を向けることができれば素晴らしいでしょう。ありがとう!

4

6 に答える 6

3

関数が呼び出された場合、exitメモリ使用量をまったくクリーンアップする必要はなく、OSによって解放されます。ただし、他のリソース(ロックファイル、クリーンな一時ファイルなど)を解放する必要がある場合は、関数を使用できますatexit。gnulibcを使用する場合は、関数を使用on_exitしてジョブを実行できます。

于 2012-09-18T15:01:16.527 に答える
2

ある条件でまたは呼び出す予定の場合func1()、またはプロセスが終了するとオペレーティングシステムが通常クリーンアップするため、メモリを解放することについて心配する必要はありません。func2()exit(1)foobar

通常の実行過程でfree適切なタイミング(終了する前)にいる限り、メモリリークは発生しません。function

于 2012-09-18T14:57:35.317 に答える
0

そういうわけで、この問題への1つの簡単なアプローチがあると思います。

以下に示すようなリソースを割り当てるときは、プログラム全体でallocCodeを維持するだけです。覚えておくべきキーポイントはほとんどありません。breakまず、switchケースでステートメントしないでください。リソースの割り当てが成功するたびに、allocCodeをインクリメントします。追加するリソースごとに、上部のスイッチに1つ大きい番号のケースを追加する必要があります。したがって、関数freeResourceBeforeExit()を呼び出すと、すべてのリソースが正しい順序で解放されます。中断がないため、スイッチケースは正しい位置から入り、エントリポイントより下にあるすべてのリソースを解放することを忘れないでください。

疑似コードを書きます。

int allocCode = 0;

int freeResourceBeforeExit()
{
    switch(allocCode)
    {
        case 4:
           free(resource3);
        case 3:
           free(resource2);
        case 2:
           free(resource1);
        case 1:
           free(resource0);
    }
    exit(0);
}


int main()
{
   ...
   resource0 = malloc(10);
   allocCode++;
   func1();
   ...
   resource1 = malloc(100);
   allocCode++;
   func2();
   ...
   resource2 = malloc(1000);
   allocCode++;
   ...
   func3();
   ...
   resource3 = malloc(10000);
   allocCode++;
   func4();
   ... 
   so on..
}

お役に立てれば !

于 2012-09-18T15:23:17.903 に答える
0

作業をいくつかの部分に分割すると、リソースの管理がはるかに簡単になります。

void part1(int arg) {
  char *foo;
  foo = (char *)malloc(sizeof(char) * 100);
  int i = func1(arg, &foo);

  free(foo);
}

void part2(void) {
  char *bar;
  bar = (char *)malloc(sizeof(char) * 100);
  int j = func2(&bar);

  free(bar);
}

void function(int arg) {
    part1(arg);
    part2();
}

これで、必要に応じて、各パーツをfree終了する前にパラメータを設定できます。

于 2012-09-18T15:38:15.593 に答える
0

原則として、バッファを解放する方法を知っているハンドラをインストールできます。ハンドラーは、を呼び出しatexitた結果として呼び出されます。使用するのはあまり快適ではありません。ハンドラーはパラメーターを取りません。つまり、解放する必要があるものを格納するには、グローバル(またはローカル静的変数)を使用する必要があります。登録を解除することはできません。つまり、リソースを自分で解放したことを示すために、これらのグローバルをnull(またはその他の特別な値)に設定する必要がありますが、ハンドラーは引き続き呼び出されます。通常は、ハンドラーを「フック」として使用し、そこから独自のリソースクリーンアップフレームワークをハングアップします。func1exitatexit

malloc実際には、プログラムが終了すると、フル機能のOSがいずれにせよ、プロセスによって予約されているすべてのメモリを解放するため、これは通常、いくつかのedバッファにとっては非常に面倒です。

終了する前にメモリを解放するのはコストがかかる場合もあります。各割り当てをで解放するfreeには、メモリが変更されます。つまり、メインメモリまたはスワップからキャッシュにドラッグする必要があります。時間がかかる可能性のある多数の小さな割り当ての場合。OSがそれを行うと、プロセスのメモリマップのマップが解除され、将来、そのアドレス空間/メモリ/スワップ空間を他のものに再利用し始めます。クリーンアップには利点がありますが(たとえば、コードを再利用しやすくし、実際のリークを見つけやすくします)、コストもかかります。

ちなみに、エラーfunc1を呼び出すexitことは、関数のユーザーに制限を課すため、関数の反社会的です。プログラムが失敗しても続行できる/実行すべきだと思っても、回復することはできませんfunc1func1事実上、プログラムが結果なしで継続することを夢見ることさえ重要であると宣言しました。はい、GMP、私はあなたを意味します。

于 2012-09-18T15:53:15.107 に答える
-2

それに対処する1つの方法:

void function() {
  int size = 100;
  char bar[size];
  char foo[size];

  // do stuff

  //compiler frees bar and foo for you
}
于 2012-09-18T14:54:53.063 に答える