[解決済み] なぜC言語の `free` は解放するバイト数を受け取らないのですか?
質問
はっきりさせておきたいのですが、私が知っているのは
malloc
と
free
はCライブラリで実装されており、通常はOSからメモリの塊を割り当て、より小さなロットのメモリをアプリケーションに小分けするための独自の管理を行い、割り当てられたバイト数を記録しています。 この問題は
free はどのようにして解放する量を知るのか
.
むしろ知りたいのは、なぜ
free
がそもそもこのように作られたのかを知りたいのです。低レベル言語である C 言語では、どのメモリがどれだけ割り当てられたかだけでなく、その量も記録するように C プログラマに求めるのは完全に合理的だと思います (実際、私は通常、とにかく割り当てられたバイト数を記録することにしています)。また、明示的にバイト数を
free
たとえば、異なる割り当てサイズに対して別々のプールを持つアロケータは、入力引数を見るだけで、どのプールから解放するかを決定することができ、全体としてより少ないスペース オーバーヘッドとなるでしょう。
というわけで、要するに、なぜ
malloc
と
free
は、内部で割り当てられたバイト数を記録するように要求されるように作成されたのでしょうか?それは単なる歴史的な事故なのでしょうか?
小さな編集です。 何人かの人が、「割り当てた量と異なる量を解放したらどうなるか」というようなポイントを提供しました。私の想像する API は、単に、割り当てられたバイト数を正確に解放することを要求することができます。私は、他の可能性についての議論を妨げたいわけではありません。
どのように解決するのか?
1つの引数
free(void *)
(Unix V7 で導入) には、以前の 2 つの引数である
mfree(void *, size_t)
に比べてもう一つ大きな利点があります。
free
は劇的にすべての
その他の
ヒープメモリで動作する他のすべての API を劇的に簡素化します。例えば、もし
free
がメモリブロックの大きさを必要としていた場合
strdup
は何らかの方法で1つの値(ポインタ)ではなく2つの値(ポインタ+サイズ)を返さなければならず、Cは複数値のリターンを単一値のリターンに比べてはるかに面倒にします。代わりに
char *strdup(char *)
の代わりに、次のように書かなければなりません。
char *strdup(char *, size_t *)
と書くか、あるいは
struct CharPWithSize { char *val; size_t size}; CharPWithSize strdup(char *)
. (最近では、NUL終端文字列が
コンピューティングの歴史の中で最も破滅的な設計バグであることを知っているからです。
しかし、それは後知恵の話です。70 年代には、C 言語が文字列を単純な
char *
として文字列を扱えるということは、実際には
Pascal や Algol といった競合製品に対する決定的な優位性であると考えられていました。
.) さらに、それは単に
strdup
だけでなく、ヒープメモリを割り当てるすべてのシステム関数やユーザ定義関数に影響します。
初期の Unix の設計者は非常に賢い人たちでした。
free
よりも
mfree
ということで、基本的には、このことに気づいて、それに従ってシステムを設計したというのが答えだと思います。その決断の瞬間に、彼らの頭の中で何が起こっていたのか、直接の記録は見つからないでしょう。しかし、私たちは想像することができます。
V6 Unix 上で動作するアプリケーションを C 言語で書いていると仮定して、その 2 つの引数である
mfree
. これまでは何とかなっていたのですが、このポインタのサイズを追跡することが、プログラムが進むにつれて面倒になってきました。
がより野心的になるにつれて
ヒープに割り当てられた変数をより多く使用する必要があるためです。しかし、そこであなたは素晴らしいアイデアを思いつきました。
size_t
を常にコピーする代わりに、割り当てられたメモリ内に直接サイズを格納するユーティリティ関数をいくつか書けばよいのです。
void *my_alloc(size_t size) {
void *block = malloc(sizeof(size) + size);
*(size_t *)block = size;
return (void *) ((size_t *)block + 1);
}
void my_free(void *block) {
block = (size_t *)block - 1;
mfree(block, *(size_t *)block);
}
そして、これらの新しい関数を使ってコードを書けば書くほど、これらの関数はより素晴らしいものに見えてきます。コードを書きやすくするだけでなく
も
はあなたのコードを
を高速化します。
-- という、あまり両立しない2つのことを実現しました。以前は、これらの
size_t
をあちこちにコピーしていたため、CPU のオーバーヘッドが増え、レジスタを頻繁に流出させなければならなくなり (特に関数の追加引数のために)、メモリも無駄になりました (関数呼び出しが入れ子になると
size_t
の複数のコピーが異なるスタックフレームに格納されるため)。新しいシステムでは、依然として
size_t
を格納するためにメモリを使う必要がありますが、それは 1 回だけで、どこにもコピーされることはありません。これらは小さな効率に見えるかもしれませんが、256 KB の RAM を搭載したハイエンド マシンの話であることに留意してください。
これであなたはハッピーです! そこであなたは、次の Unix リリースに取り組んでいる髭面の男性たちとあなたのクールなトリックを共有しますが、それは彼らを幸せにするのではなく、悲しませることになります。ちょうどその頃、彼らは
strdup
のような新しいユーティリティ関数をたくさん追加しているところで、あなたのクールなトリックを使っている人たちは、彼らの新しい関数を使うことができないことに気づきました。そしてそれはあなた自身も悲しくなります。
strdup(char *)
関数を自分で書き直さなければならないことに気づくからです。
しかし、待ってください! これは 1977 年の話であり、後方互換性はあと 5 年は発明されないでしょう! それに、まじめな人は誰も実際に
を使うことはありません。
この無名の "Unix" を使っている人はいないのです。K&Rの初版は今出版社に向かっているところですが、それは問題ありません--最初のページには「Cは文字列のような複合オブジェクトを直接扱う操作を提供しない...ヒープもない..."」と書いてあるのです。この時点では
string.h
と
malloc
はベンダーの拡張機能です(!)。そこで、ヒゲ男1号が提案するのは、それらを好きなように変更することができるということです。トリッキーなアロケータを宣言するのは
公式
アロケータであると宣言してはどうでしょうか?
数日後、髭男爵 2 号は新しい API を見て、ちょっと待てよ、これは前より良くなっているが、サイズを保存するために 1 回の割り当てごとに単語全体を費やしている、と言いました。彼はこれを神への冒涜と見なしました。他のみんなは、彼がおかしいという目で見ています。その夜、彼は遅くまで残って新しいアロケーターを発明しました。それはサイズを全く保存せず、代わりにポインター値に対して黒魔術のビットシフトを行うことでサイズをその場で推測し、新しいAPIをそのままにそれをスワップするものでした。新しい API は、誰もその切り替えに気づかないことを意味しますが、翌朝、コンパイラが使用する RAM が 10% 少ないことに気づきます。
そして今、誰もが満足しています。あなたは書きやすく高速なコードを手に入れ、ひげ男 1 号はシンプルで素敵な
strdup
を書くことができ、ひげ男2号はちょっとだけ得をした気分になって
quines をいじくり回す
. 出荷しろ!
少なくとも、そのような は が起こったのです。
関連
-
[解決済み] Linuxカーネルにおけるcontainer_ofマクロの理解
-
[解決済み] C言語では「?」演算子は何をするのですか?
-
[解決済み] 配列の場合、なぜ a[5] == 5[a] になるのでしょうか?
-
[解決済み] Cプリプロセッサはなぜ "linux "という単語を定数 "1 "と解釈するのですか?
-
[解決済み] 8192個の要素にループをかけると、プログラムが遅くなるのはなぜですか?
-
[解決済み] char s[]とchar *sの違いは何ですか?
-
[解決済み] C言語でファイルが存在するかどうかを確認する最も良い方法は何ですか?
-
[解決済み] C言語のi++と++iに性能差はあるのでしょうか?
-
[解決済み] フリーは、どのように無料化を知っているのですか?
-
[解決済み] C言語プログラミング言語」の本には、なぜmallocをキャストしなければならないと書いてあるのですか?
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
C 構造体定義エラー: '['トークンの前に一次式があることが予想される
-
構造体の配列--[エラー] '['トークンの前に一次式があることが予想される
-
libc++abi.dylib: NSException タイプの捕捉されない例外で終了するエラー
-
[解決済み] char *とchar[]の違い [重複]
-
[解決済み] Linuxカーネルにおけるcontainer_ofマクロの理解
-
[解決済み] C関数から文字列を返す
-
[解決済み] C言語における「static」の意味とは?
-
[解決済み] ++iとi++の違いは何ですか?
-
[解決済み] フリーは、どのように無料化を知っているのですか?
-
[解決済み] ptr が NULL の場合の free(ptr) はメモリを破壊するか?