私はC++ポインタで遊んでいます。ポインタにメモリを割り当てましたが、後で解放しませんでした。次にプログラムを実行したときに、ポインターが同じアドレスにあるのはなぜですか? OSはそのアドレスが占有されていると見なして、メモリリークを発生させるべきではありませんか?
int* a = new int[1]; //or (int*) malloc(1);
cout << &a << endl; //always 0x28fe98
私はC++ポインタで遊んでいます。ポインタにメモリを割り当てましたが、後で解放しませんでした。次にプログラムを実行したときに、ポインターが同じアドレスにあるのはなぜですか? OSはそのアドレスが占有されていると見なして、メモリリークを発生させるべきではありませんか?
int* a = new int[1]; //or (int*) malloc(1);
cout << &a << endl; //always 0x28fe98
いくつかの誤解...
式&a
は、変数のアドレスa
、つまり、pointer-to-pointer-to-int 型のポインターのアドレスです。それ自体の値は関係ありませんa
。つまり、初期化されているかどうかに関係なく、そのアドレスは同じです。あなたはおそらくやりたいcout << a << std::endl;
プログラムを実行するたびに、OS はまったく新しいアドレス空間を割り当て、プログラムの終了時にそれを解放します。そのため、メモリを解放しなくても、プログラムの終了時に解放されます。また、プログラムが終了しなくても、各プロセスには独自のアドレス空間があるため、一方に割り当てられたメモリが他方のメモリに影響を与えることはありません。
なんらかの形式の仮想空間のランダム化が (セキュリティ目的で) 使用されない限り、同じプログラムを何度か実行すると、多かれ少なかれ同じアドレスが生成されるのは当然のことです。
とにかく、C++ には基本的に 3 種類のメモリがあることを覚えておいてください: 静的 (グローバル変数)、自動 (ローカル変数)、および動的 (新しいオブジェクト)。あなたの例では、a
( with address &a
) は自動または静的であり、コンテキストからは明確ではありませんが、a
(address a
) が指す整数は動的です。3 つすべてを試してみて、それらの違いを確認してください。
特に興味深い実験は、再帰関数のローカル変数のアドレスです。
void rec(int x)
{
cout << x << ": " << &x << endl;
if ( x > 0)
rec(x - 1);
}
プログラムを再度実行すると、前回の実行が終了したことを意味します。これは、OS がメモリを再利用したことを意味します。メモリ リークは、アプリケーションが終了した後でも、メモリが永久にアプリに予約されているという意味ではありません。OSはそれよりも賢いです。
new がアドレスを返している間、変数のアドレスを出力しています。
すなわち
cout << a << endl;
もう少し明確にするために、コンパイラが生成したオフセット(プロセスがロードされる場所へのオフセット)が表示されるため、プロセスがロードされる場所にも依存しません。プロセスの開始アドレスは、プロセッサ内のレジスタに格納されます。
その前に別の宣言を追加すると、別のアドレスが表示されると思います。
お気に入り
int b=0;
int * a = new int[1];
これで、再コンパイルして実行すると変更が表示され、別のアドレスが表示されるはずです。
プログラムが終了した場合、メモリはそのプログラム用に予約されていません。もちろん、ポインタは常にそのメモリアドレスを指しているわけではなく、これまでに実行するたびに起こりました。さらにいくつかのプログラムを開いて再度実行すると、アドレスが変更される可能性があります。
プログラムを終了すると、プログラムによって割り当てられたメモリを解放するよう OS に指示されます。
どうやら、その後の実行で使用するために割り当てるために同じメモリアドレスを選択したようです。