5

問題の言語は C/C++ です。

私の教授は、使用が終わったらヒープ上のメモリを解放するように言いました。そうしないと、アクセスできないメモリになってしまう可能性があるからです。これに関する問題は、すべてのメモリが使い果たされてしまい、いずれにもアクセスできなくなる可能性があることです。

同じ概念がスタックに適用されないのはなぜですか? スタック上で使用したメモリにいつでもアクセスできることは理解していますが、新しい変数を作成し続けると、最終的にスペースが不足しますよね? では、スタックの変数を解放して、ヒープのように新しい変数用のスペースを空けないのはなぜでしょうか?

コンパイラがスタック上の変数を解放していることがわかりますが、それは変数のスコープの最後にあります。スコープの最後でヒープ上の変数も解放しませんか? そうでない場合、なぜですか?

4

7 に答える 7

8

動的に割り当てられたオブジェクト (口語で「ヒープ オブジェクト」) は決して変数ではありません。したがって、それらが範囲外になることはありません。それらはどのスコープ内にも住んでいません。それらを処理できる唯一の方法は、割り当て時に取得するポインターを使用することです。

(通常、ポインターは変数に割り当てられますが、それは役に立ちません。)

繰り返す:変数には有効範囲があります。オブジェクトはしません。しかし、多くのオブジェクト変数です。

質問に答えるには:オブジェクトのみを解放でき、変数は解放できません。

于 2013-11-03T00:02:55.047 に答える
3

閉じた "}" 波括弧の終わりは、スタックがそのメモリを "解放" する場所です。だから私が持っている場合:

{
    int a = 1;
    int b = 2;

    {
        int c = 3; // c gets "freed" at this "}" - the stack shrinks
                   // and c is no longer on the stack.
    }
}                  // a and b are "freed" from the stack at this last "}".

c はスタック上で "a" や "b" よりも "上位" にあると考えることができるため、c はそれらの前にポップされます。したがって、「}」記号を書き込むたびに、効果的にスタックが縮小され、データが「解放」されます。

于 2013-11-03T00:02:40.000 に答える
2

では、スタックの変数を解放して、ヒープのように新しい変数用のスペースを空けないのはなぜでしょうか?

「スタックアロケータ」が知っているすべての情報はESP、スタックの一番下へのポインタです。

   N: used
 N-1: used
 N-2: used
 N-3: used <- **ESP**
 N-4: free
 N-5: free
 N-6: free
 ...

これにより、「スタック割り当て」が非常に効率的になります。割り当てESPのサイズだけ減少するだけでなく、ローカリティ/キャッシュに適しています。

さまざまなサイズの任意の割り当て解除を許可すると、「スタック」が「ヒープ」になり、関連する追加のオーバーヘッドがすべて発生しESPますが、どのスペースが割り当て解除され、どのスペースが割り当て解除されていないかを覚えておく必要があるため、十分ではありません。

   N: used
 N-1: free
 N-2: free
 N-3: used
 N-4: free
 N-5: used
 N-6: free
 ...

明らかに -ESPでは十分ではありません。また、断片化の問題にも対処する必要があります。

コンパイラがスタック上の変数を解放していることがわかりますが、それは変数のスコープの最後にあります。スコープの最後でヒープ上の変数も解放しませんか? そうでない場合、なぜですか?

理由の 1 つは、常にそれを望んでいるとは限らないことです。割り当てられたデータを関数の呼び出し元に返したい場合があります。そのデータは、作成されたスコープより長く存続する必要があります。

そうは言っても、「ヒープ」に割り当てられたデータのスコープベースの有効期間管理が本当に必要な場合 (そしてほとんどの場合、実際にはスコープベースです)、C++ ではそのようなデータの周りにラッパーを使用するのが一般的です。例の1つは次のstd::vectorとおりです。

{
    std::vector<int> x(1024); // internally allocates array of 1024 ints on heap
    // use x
    // ...
} // at the end of the scope destructor of x is called automatically,
  // which does deallocation
于 2013-11-03T00:06:40.113 に答える
0

ヒープはコードによって管理されます: ヒープ割り当ての削除は、ヒープ マネージャーを呼び出すことによって行われます。スタックはハードウェアによって管理されます。電話するマネージャーはいません。

于 2013-11-03T00:36:51.373 に答える
0

関数呼び出しについて読む - 各呼び出しはデータと関数アドレスをスタックにプッシュします。関数はスタックからデータをポップし、最終的にその結果をプッシュします。

一般に、スタックは OS によって管理されます。はい、枯渇する可能性があります。次のようなことを試してみてください:

int main(int argc, char **argv)
     {
     int table[1000000000];
     return 0;
     }

それは十分に早く終わるはずです。

于 2013-11-03T00:00:34.350 に答える
0

スタック上のローカル変数は実際には解放されません。現在のスタックを指しているレジスタは上に移動され、スタックはそれらを「忘れます」。そして、はい、オーバーフローしてプログラムがクラッシュするほど多くのスタックスペースを占有する可能性があります.
ヒープ上の変数は、プログラムの終了時にオペレーティング システムによって自動的に解放されます。もしあなたがそうするなら

int x;
for(x=0; x<=99999999; x++) {
  int* a = malloc(sizeof(int));
}

a の値が上書きされ続け、a が格納されていたヒープ内の場所が失われます。プログラムは終了しないため、このメモリは解放されません。これを「メモリリーク」と呼びます。最終的に、ヒープ上のすべてのメモリを使い果たし、プログラムがクラッシュします。

于 2013-11-03T00:06:18.007 に答える