[解決済み】malloc()とfree()はどのように動作するのですか?
質問
を知りたい。
malloc
と
free
の作業を行います。
int main() {
unsigned char *p = (unsigned char*)malloc(4*sizeof(unsigned char));
memset(p,0,4);
strcpy((char*)p,"abcdabcd"); // **deliberately storing 8bytes**
cout << p;
free(p); // Obvious Crash, but I need how it works and why crash.
cout << p;
return 0;
}
可能であれば、メモリレベルで深く掘り下げて回答していただけると、本当にありがたいです。
どのように解決するのですか?
mallocについては、すでにいくつかの回答が投稿されているので、OKです。
もっと興味深いのは フリーの仕組み (この方向で、mallocもよりよく理解することができます)。
malloc/freeの実装の多くでは、freeは通常OSにメモリを返しません(少なくとも稀なケースです)。その理由は、ヒープに隙間ができてしまうからで、2GBや4GBの仮想メモリを隙間だらけのまま終わらせてしまうことがあります。これは避けるべきです。仮想メモリを使い切ったとたんに、大きな問題が発生するからです。もうひとつは、OSが特定のサイズとアライメントを持つメモリチャンクしか扱えないことです。具体的に言うと 通常、OSは仮想メモリ・マネージャが扱えるブロック(多くの場合、512バイトの倍数、例えば4KB)しか扱えません。
だから、40ByteをOSに返しても、うまくいかない。では、freeはどうするのか?
Freeはメモリブロックを自分の空きブロックリストに入れます。通常は、アドレス空間内の隣接するブロックを結合することも試みます。フリーブロックリストとは、単なるメモリチャンクの循環リストであり、その先頭には何らかの管理データが含まれています。これは、標準のmalloc/freeで非常に小さなメモリ要素を管理するのが効率的でない理由でもあります。すべてのメモリチャンクは追加データを必要とし、サイズが小さいほど断片化が進みます。
また、フリーリストは、新しいメモリチャンクが必要になったときに、mallocが最初に見る場所でもあります。OSから新しいメモリを要求する前にスキャンされるのです。必要なメモリより大きなチャンクが見つかると、それは2つの部分に分割されます。1つは呼び出し元に返され、もう1つは空きリストに戻されます。
この標準的な動作には、さまざまな最適化があります(たとえば、メモリの小さなチャンクの場合など)。しかし、mallocとfreeは非常に普遍的でなければならないので、代替案が使えない場合は常に標準的な動作がフォールバックされます。例えば、チャンクをサイズ順に並べたリストに格納するなど、free-listの処理にも最適化があります。しかし、すべての最適化にはそれなりの限界があります。
なぜあなたのコードはクラッシュするのですか。
その理由は、4 文字分のサイズの領域に 9 文字(末尾のヌルバイトを忘れないでください)を書き込むと、おそらくあなたのデータチャンクの後ろに存在する別のメモリチャンクの管理データを上書きしてしまうからです(このデータはほとんどの場合、メモリチャンクの前に"格納されるからです)。free があなたのチャンクを空きリストに入れようとすると、この管理用データに触れてしまい、上書きされたポインターにつまずく可能性があります。これはシステムをクラッシュさせます。
これは、むしろ優雅な動作です。また、どこかで暴走したポインタがメモリ解放リストのデータを上書きしてしまい、システムがすぐにはクラッシュせず、いくつかのサブルーチンが後にクラッシュした状況も見たことがあります。中程度の複雑さのシステムであっても、このような問題はデバッグが本当に大変です。私が関わったケースでは、クラッシュの原因がメモリダンプで示された場所とはまったく異なる場所にあったため、その原因を見つけるのに数日かかりました(より多くの開発者のグループが)。時限爆弾のようなものです。次の "free" や "malloc" がクラッシュするのは分かっていても、その理由が分からないのですから。
これらはC/C++の最悪の問題であり、ポインタが問題になる理由の1つでもあります。
関連
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み] error: 'ostream' does not name a type.
-
[解決済み】#include<iostream>は存在するのですが、「識別子 "cout "は未定義です」というエラーが出ます。なぜですか?
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み] 文字列の単語を反復処理するにはどうすればよいですか?
-
[解決済み] 1ビットのセット、クリア、トグルはどのように行うのですか?
-
[解決済み] mallocの結果はキャストするのですか?
-
[解決済み] mallocとcallocの違い?
-
[解決済み] プログラム終了前にmallocの後にfreeをしないと本当に何が起こるのか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 unsigned int vs. size_t
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】fpermissiveフラグは何をするのですか?
-
[解決済み] 式はクラス型を持つ必要があります。
-
[解決済み】指定範囲内の乱数で配列を埋める(C++)
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された