チャンクはデータを保有したり、解放した空き領域、未使用の空き領域を管理するためのオブジェクトです。
チャンクには 3 種類あります。
割り当て済みチャンクは、Cのプログラムからアクセスできるチャンクですね。
フリーチャンクは free() 関数等で割り当て済みチャンクを解放したものです。
割り当てを行う際には、フリーチャンクを連結したフリーリストというデータ構造から、適当なサイズのチャンクを探してそれを再利用できます。
トップチャンクは未使用のデータ領域のボーダーのアドレスを見つけるためのタグみたいなものです。
これら 3 種類のチャンクは malloc_chunk 構造体の状態として表現できます。
では構造体の定義を見てみましょう。
malloc.c(https://github.com/MacKomatsu/glibc/blob/release/2.27/master/malloc/malloc.c).
1002 /* Forward declarations. */ 1003 struct malloc_chunk; 1004 typedef struct malloc_chunk* mchunkptr;
malloc.c(https://github.com/MacKomatsu/glibc/blob/release/2.27/master/malloc/malloc.c).
1054 /* 1055 This struct declaration is misleading (but accurate and necessary). 1056 It declares a "view" into memory allowing access to necessary 1057 fields at known offsets from a given base. See explanation below. 1058 */ 1059 1060 struct malloc_chunk { 1061 1062 INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */ 1063 INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */ 1064 1065 struct malloc_chunk* fd; /* double links -- used only if free. */ 1066 struct malloc_chunk* bk; 1067 1068 /* Only used for large blocks: pointer to next larger size. */ 1069 struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */ 1070 struct malloc_chunk* bk_nextsize; 1071 };
mchunk_previous_size は前のチャンクのサイズですが、フリーリストの連結に使われます。
mchunk_size は下 3 桁分をフラグに使ったチャンクサイズです。
フラグについては以下の図を見てください。
まあ構造は初めて見ると複雑に見えるかと思いますがね。
それでフラグには以下の 3 種類が存在します。
Aは 0x4 に相当し M は 0x2、そして P は 0x1 として表現されます。
ペイロードはアプリケーションの使用するユーザーデータに相当します。
もしお疑いであれば malloc.c のコメントを確認すると良いでしょう。
/* 1091 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1092 | Size of previous chunk, if unallocated (P clear) | 1093 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1094 | Size of chunk, in bytes |A|M|P| 1095 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1096 | User data starts here... . 1097 . . 1098 . (malloc_usable_size() bytes) . 1099 . | 1100 nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1101 | (size of chunk, but used for application data) | 1102 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1103 | Size of next chunk, in bytes |A|0|1| 1104 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
つまりユーザーデータはチャンクサイズのすぐ次に来ることになります。
割り当て済みの領域は malloc_chunk 構造体の疑似バージョンと言えるかもしれませんね。
ユーザーデータを強引に入れたって感じです。
反対にフリーチャンクは以下のように malloc_chunk 構造体のパラメーターをフル活用できます。
奇妙に感じられた方は malloc.c の以下のコメントをチェックしてみてくださいね。
/* 1116 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1117 | Size of previous chunk, if unallocated (P clear) | 1118 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1119 `head:' | Size of chunk, in bytes |A|0|P| 1120 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1121 | Forward pointer to next chunk in list | 1122 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1123 | Back pointer to previous chunk in list | 1124 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1125 | Unused space (may be 0 bytes long) . 1126 . . 1127 . | 1128 nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1129 `foot:' | Size of chunk, in bytes | 1130 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1131 | Size of next chunk, in bytes |A|0|0| 1132 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */
これを図に直すと以下のようになります。
fd_nextsize と bk_nextsize は大きめのフリーチャンク(large free chunk)の時のみに使われるらしいです。
なので小さめのフリーチャンク(small free chunk)の時には fd_nextsize と bk_nextsize は使われません。
ちなみにフリーチャンクについては大きさによって、保存されるデータ構造が異なります。
このチャンクを収納してくれるデータ構造を bin と呼びます。
bin はポインターの配列ですが、
ビンの詳細は後で説明しますが、どのビンに入るかによってチャンクの内部データが変動します。
Copyright 2018-2019, by Masaki Komatsu