固定サイズブロックでは、説明したのはフリーリストです。これは非常に一般的な手法で、次の点があります。空きブロックのリストは、空きブロック自体に保存されます。Cコードでは、次のようになります。
static void *alloc_ptr = START_OF_BIG_SEGMENT;
static void *free_list_head = NULL;
static void *
allocate(void)
{
void *x;
if (free_list_head == NULL) {
x = alloc_ptr;
alloc_ptr = (char *)alloc_ptr + SIZE_OF_BLOCK;
} else {
x = free_list_head;
free_list_head = *(void **)free_list_head;
}
return x;
}
static void
release(void *x)
{
*(void **)x = free_list_head;
free_list_head = x;
}
これは、割り当てられたすべてのブロックが同じサイズであり、そのサイズがポインターのサイズの倍数である限りうまく機能するため、アライメントは維持されます。割り当てと割り当て解除は一定の時間です(つまり、メモリアクセスと基本的な追加と同じくらいの時間です-現代のコンピュータでは、メモリアクセスにはキャッシュミス、さらには仮想メモリ、したがってディスクアクセスが含まれる可能性があるため、「一定時間」かなり大きくなる可能性があります)。メモリのオーバーヘッドはありません(追加のブロックごとのポインターなどはありません。割り当てられたブロックは連続しています)。また、割り当てポインターは、一度に多くのブロックを割り当てなければならなかった場合にのみ所定のポイントに到達します。割り当てはフリーリストの使用を優先するため、割り当てポインターは、現在のポインターの下のスペースがクロックでいっぱいになった場合にのみ増加します。その意味で、 技術。
減少リリース後の割り当てポインタはより複雑になる可能性があります。これは、フリーブロックを予測できない順序で処理するフリーリストに従うことによってのみフリーブロックを確実に識別できるためです。可能な場合に大きなセグメントサイズを小さくすることが重要な場合は、オーバーヘッドを増やして別の手法を使用できます。割り当てられた2つのブロックの間に「穴」を開けます。穴は、メモリ順に二重にリンクされたリストでリンクされています。穴の終了位置を知ることで穴の開始アドレスを特定できるように、穴のデータ形式が必要です。また、穴がメモリのどこで始まるかがわかっている場合は、穴のサイズも必要です。次に、ブロックをリリースすると、次の穴と前の穴とマージする穴を作成し、すべての穴の順序付きリストを再構築します(一定時間内に)。オーバーヘッドは、割り当てられたブロックごとに約2ポインターサイズの単語です。しかし、その価格で、「最終的な穴」の発生、つまり大きなセグメントサイズを小さくする機会を確実に検出できます。
多くの可能なバリエーションがあります。入門書としては、Dynamic Storage Allocation:A Survey and Critical Review by Wilson et al。