Bei Blöcken mit fester Größe ist das, was Sie beschrieben haben, eine freie Liste . Dies ist eine sehr verbreitete Technik mit der folgenden Wendung: Die Liste der freien Blöcke wird in den freien Blöcken selbst gespeichert. In C-Code würde das so aussehen:
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;
}
Dies funktioniert gut, solange alle zugewiesenen Blöcke dieselbe Größe haben und diese Größe ein Vielfaches der Größe eines Zeigers ist, sodass die Ausrichtung erhalten bleibt. Zuweisung und Freigabe erfolgen in konstanter Zeit (dh so konstant wie Speicherzugriffe und elementare Ergänzungen). In einem modernen Computer kann ein Speicherzugriff Cachefehler und sogar virtuellen Speicher, also Festplattenzugriffe, zur Folge haben. kann ziemlich groß sein). Es gibt keinen Speicheraufwand (keine zusätzlichen Zeiger pro Block oder ähnliches; die zugewiesenen Blöcke sind zusammenhängend). Außerdem erreicht der Zuweisungszeiger nur dann einen bestimmten Punkt, wenn zu einem Zeitpunkt so viele Blöcke zugewiesen werden mussten: Da die Zuweisung die freie Liste bevorzugt, wird der Zuweisungszeiger nur erhöht, wenn der Raum unter dem aktuellen Zeiger taktvoll ist. In diesem Sinne, Technik.
AbnehmendDer Zuweisungszeiger nach einer Freigabe kann komplexer sein, da freie Blöcke nur durch Befolgen der freien Liste, die sie in unvorhersehbarer Reihenfolge durchläuft, zuverlässig identifiziert werden können. Wenn es für Sie wichtig ist, die Größe des großen Segments nach Möglichkeit zu verringern, können Sie eine alternative Technik mit mehr Overhead verwenden: Zwischen zwei zugewiesenen Blöcken wird ein "Loch" eingefügt. Die Löcher werden mit einer doppelt verknüpften Liste in der Speicherreihenfolge miteinander verknüpft. Sie benötigen ein Datenformat für eine Bohrung, damit Sie die Bohrungsstartadresse ermitteln können, indem Sie wissen, wo sie endet, und auch die Bohrungsgröße, wenn Sie wissen, wo die Bohrung im Speicher beginnt. Wenn Sie dann einen Block freigeben, erstellen Sie eine Bohrung, die Sie mit der nächsten und der vorherigen Bohrung zusammenführen. Dabei wird (noch in konstanter Zeit) die geordnete Liste aller Bohrungen neu erstellt. Der Overhead beträgt dann ungefähr zwei Wörter in Zeigergröße pro zugewiesenem Block; Zu diesem Preis können Sie jedoch zuverlässig das Auftreten eines "endgültigen Lochs" erkennen, dh eine Gelegenheit, die Größe des großen Segments zu verringern.
Es gibt viele mögliche Variationen. Ein gutes Einführungspapier ist Dynamic Storage Allocation: Eine Umfrage und eine kritische Überprüfung von Wilson et al.