静的メモリ割り当てと動的メモリ割り当ての違いは何ですか?
これを例で説明できますか?
静的メモリ割り当てと動的メモリ割り当ての違いは何ですか?
これを例で説明できますか?
これは標準的な面接の質問です。
calloc()
、malloc()
およびフレンドを使用して実行時に割り当てられるメモリです。ヒープ データ構造refとは関係ありませんが、「ヒープ」メモリと呼ばれることもあります。
int * a = malloc(sizeof(int));
free()
が呼び出されるまで、ヒープ メモリは永続的です。つまり、変数の有効期間を制御します。
これは一般に「スタック」メモリとして知られているもので、新しいスコープに入ったときに割り当てられます (通常、新しい関数がコール スタックにプッシュされるとき)。範囲外に移動すると、自動メモリ アドレスの値は未定義になり、それらにアクセスするとエラーになります。
int a = 43;
スコープは必ずしも機能を意味しないことに注意してください。スコープは関数内でネストでき、変数は宣言されたブロック内でのみスコープ内になります。このメモリが割り当てられる場所は指定されていないことにも注意してください。(正常なシステムでは、スタック上にあるか、最適化のために登録されます)
コンパイル時に割り当てられます*。静的メモリ内の変数の有効期間は、プログラムの有効期間です。
static
C では、キーワードを使用して静的メモリを割り当てることができます。スコープはコンパイル単位のみです。
キーワードを考慮すると、extern
物事はより興味深いものになります。extern
変数が定義されると、コンパイラは変数にメモリを割り当てます。extern
変数が宣言されている場合、コンパイラは変数を別の場所で定義する必要があります。変数の宣言/定義に失敗するextern
とリンクの問題が発生し、変数の宣言/定義に失敗するstatic
とコンパイルの問題が発生します。
ファイル スコープでは、 static キーワードはオプションです (関数外)。
int a = 32;
ただし、関数スコープ内ではありません (関数内):
static int a = 32;
技術的には、extern
とstatic
は C の変数の 2 つの別個のクラスです。
extern int a; /* Declaration */
int a; /* Definition */
特に、コンパイル マシンとホスト マシンが同じではないか、同じアーキテクチャ上にない可能性があることを考慮し始めると、コンパイル時に静的メモリが割り当てられると言うのはやや混乱します。
静的メモリの割り当ては、コンパイル時に割り当てられるのではなく、コンパイラによって処理されると考えたほうがよいかもしれません。
たとえば、コンパイラはdata
コンパイルされたバイナリに大きなセクションを作成する場合があり、プログラムがメモリにロードされると、data
プログラムのセグメントは、割り当てられたメモリの場所として使用されます。これには、大量の静的メモリを使用する場合、コンパイルされたバイナリが非常に大きくなるという顕著な欠点があります。半ダース未満のコード行から生成された数ギガバイトのバイナリを作成することは可能です。もう 1 つのオプションは、プログラムが実行される前に、別の方法でメモリを割り当てる初期化コードをコンパイラが挿入することです。このコードは、ターゲット プラットフォームと OS によって異なります。実際には、最新のコンパイラはヒューリスティックを使用して、これらのオプションのどれを使用するかを決定します。10k、1m、10m、100m、1G、または 10G 項目の大きな静的配列を割り当てる小さな C プログラムを作成することで、これを自分で試すことができます。多くのコンパイラでは、バイナリ サイズは配列のサイズに比例して増加し続け、特定のポイントを超えると、
最後のメモリ クラスは「レジスタ」変数です。予想どおり、レジスタ変数は CPU のレジスタに割り当てる必要がありますが、実際の決定はコンパイラに委ねられています。address-of を使用してレジスタ変数を参照に変換することはできません。
register int meaning = 42;
printf("%p\n",&meaning); /* this is wrong and will fail at compile time. */
最近のほとんどのコンパイラは、どの変数をレジスタに入れるかを選ぶのがあなたよりも賢いです:)
割り当てには、静的、自動、および動的の 3 つのタイプがあります。
静的割り当てとは、プログラムの開始時に変数のメモリが割り当てられることを意味します。サイズはプログラム作成時に固定されます。これは、グローバル変数、ファイル スコープ変数、およびstatic
定義された内部関数で修飾された変数に適用されます。
自動メモリ割り当ては、関数内で定義された (非静的) 変数に対して発生し、通常はスタックに格納されます(ただし、C 標準ではスタックの使用が義務付けられていません)。それらを使用して追加のメモリを予約する必要はありませんが、一方で、このメモリの有効期間に対する制御も制限されています。例: 関数内の自動変数は、関数が終了するまでしか存在しません。
void func() {
int i; /* `i` only exists during `func` */
}
動的メモリ割り当ては少し異なります。これらのメモリ ロケーションの正確なサイズと有効期間を制御できるようになりました。解放しないと、メモリ リークが発生し、アプリケーションがクラッシュする可能性があります。これは、ある時点でシステムがより多くのメモリを割り当てることができないためです。
int* func() {
int* mem = malloc(1024);
return mem;
}
int* mem = func(); /* still accessible */
上の例では、関数が終了しても、割り当てられたメモリは有効でアクセス可能です。メモリの使用が終わったら、解放する必要があります。
free(mem);
静的メモリ割り当て:コンパイラは、宣言された変数に必要なメモリ空間を割り当てます。演算子のアドレスを使用して、予約されたアドレスを取得し、このアドレスをポインタ変数に割り当てることができます。宣言された変数のほとんどは静的メモリを持っているため、これはポインター変数にポインター値を割り当てる方法は、静的メモリ割り当てとして知られています。メモリはコンパイル時に割り当てられます。
動的メモリ割り当て: malloc( ) や calloc( ) などの関数を使用してメモリを動的に取得します。これらの関数を使用してメモリを動的に取得し、これらの関数によって返される値がポインタ変数に割り当てられている場合、そのような割り当ては動的メモリと呼ばれます。 allocation.memory は実行時に割り当てられます。
静的メモリ割り当て:
動的メモリ割り当て:
静的メモリ割り当て。割り当てられたメモリはスタックになります。
int a[10];
動的メモリ割り当て。割り当てられたメモリはヒープになります。
int *a = malloc(sizeof(int) * 10);
C にはガベージ コレクター (GC) がないため、後者はfree d にする必要があります。
free(a);