-1

スタックとヒープがどのように成長するかを確認するために、malloced メモリとローカル変数をいじっていました。私の理解では、ヒープは上向きに成長し、スタックは下向きに成長します。malloc を使用して割り当てられたメモリはすべてヒープに割り当てられ、ローカル変数は関数内のスタックに割り当てられます。

次のプログラムでは:

#include <stdio.h>
#include <stdlib.h>
#define SIZE 999999999
void tot(){
    static int c =0;
    int k;
    c++;
    int *pp = malloc(sizeof(int) * SIZE);
    if(pp==NULL){
        fprintf(stderr,"NO memory allocated after call : %d\n",c);
        return;
    }
        printf("%p %d %p\n",&k,c,pp);
        tot();
}

int main(int argc, char *argv[]){
    int k;
    int *pp = malloc(sizeof(int) * 99999);
    if(pp ==NULL){
        fprintf(stderr,"No memory allocated\n");
        return;
    }
        printf("%p %p\n",&k,pp);
        tot();
        return 0;
}

関数 tot() に 4 バイトのローカル変数を 1 つ作成し、int* 型のポインター変数を 1 つ作成しました。これにより、各呼び出しの合計スタック サイズが 4 バイトよりわずかに大きくなります。また、malloc を使用してメモリを割り当て、割り当てられたメモリをローカル ポインタ変数に割り当てました。この malloced メモリはヒープに割り当てられるため、スタック サイズは 4 バイトをわずかに超えるはずですが、上記のプログラムで観察したところ、スタック サイズが大幅に増加しています。その大量の計算を行った後、スタック フレームには、各関数呼び出しで作成された割り当てられたメモリが含まれていることがわかりました。

線を抜いても

int *pp = (int*)malloc(sizeof(int) * SIZE);

これは、各関数呼び出しでこの大きなメモリを割り当てる責任があり、スタック フレームのサイズを ~4 バイトに減らします。これは完全に問題ありません。

ただし、スタック フレームは両方の状況で下向きに成長しています。

なぜ私はそのような出力を得ているのですか。動的メモリがヒープに割り当てられているという私の考えは間違っていますか。malloced メモリがスタック フレームのサイズを増やしているのはなぜですか?

EDIT:私はまた、1つのスタックフレームに割り当てられたメモリへのポインタを他の関数呼び出し(別のスタックフレーム)に渡すことによって、他のスタックフレームの1つのスタックフレームに割り当てられたメモリにアクセスしようとしました。コンパイラが malloc を alloca に内部的に変換していないかどうかを確認するための他の呼び出し (これが大きなスタック フレームの原因である可能性があります) が、違いはありませんでした。結果はまだ同じです。

4

2 に答える 2

1

C は低水準言語ですが、依然として定義が緩いため、特定の詳細がプラットフォーム間で異なる可能性があります。たとえば、コンパイラは、実行中のプログラムの結果が変更されない限り、適切と思われるさまざまな量のスタック スペース (通常は「余分な」スペース) を自由に割り当てることができます。

これは、パフォーマンス [1] の名目で、または特定の呼び出し規約をサポートするために行われる場合があります。そのため、int がバイト単位のスペースしか必要としない場合でも、コンパイラはスタックに 16 バイトを割り当てて、適切なメモリ アラインメントを維持することができます。

スタックサイズの「大きな」増加が SIZE に比べて小さい場合、その違いはおそらくこの種のパディングによるものです。(スタックには、ローカル変数だけでなく、より多くのデータもあることに注意してください。通常、呼び出し元の関数の戻りアドレスがそこに格納されます。また、コンパイラーが呼び出し元から格納する必要があると判断したレジスタの内容も格納されます。)

実際にmallocスタックに割り当てているように見える場合 (つまり、スタックが SIZE のジャンプで増加している場合)、それは驚くべきことですが、おそらくコンパイラに代わって「正しい」でしょう。定義によりmalloc、メモリを割り当てます。これがヒープから割り当てられるという保証はありませんが、それは確かに通常の実装です。の結果は、mallocそれが呼び出されたスタック フレームの外部からアクセスされることはないため、コンパイラ原則としてこれをalloca呼び出しに最適化できます。しかし、繰り返しになりますが、私はそれを見て非常に驚くでしょう.

[1] 例: http://software.intel.com/en-us/articles/data-alignment-when-migrating-to-64-bit-intel-architecture

于 2013-05-05T16:52:14.310 に答える