0Pricing
C Academy · Lektion

Wie malloc funktioniert

Der Heap und Freilisten.

Wie malloc funktioniert ist eine kostenlose C Academy-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C Academy-Kurs umfasst insgesamt 4 Lektionen.

Was malloc wirklich macht

Wenn Sie malloc(n) aufrufen, gibt Ihnen die C-Bibliothek einen Zeiger auf mindestens n nutzbare Bytes. Der Heap ist jedoch lediglich ein Bereich des Prozessspeichers, den der Allocator für Sie verwaltet.

Die Aufgabe des Allocators besteht in der Verwaltung: Er verfolgt, welche Bytes verwendet und welche frei sind, und sorgt dafür, dass freigegebener Speicher effizient wiederverwendet wird.

Der Heap kommt vom Betriebssystem

Der Allocator erzeugt Speicher nicht aus dem Nichts. Er fordert das Betriebssystem über Systemaufrufe wie brk/sbrk oder mmap in großen Blöcken an.

Anschließend teilt er diese Blöcke für Ihre malloc-Aufrufe in kleinere Bereiche auf. Da Anfragen an das Betriebssystem teuer sind, fordern Allocators Speicher gesammelt an und verwenden ihn wieder.

/* Conceptual: grow the heap by 4096 bytes */
void *base = sbrk(4096);
if (base == (void *)-1) {
    /* out of memory */
}

sbrk und der Program Break

sbrk(n) verschiebt den „Program Break“ um n Bytes nach oben und gibt den vorherigen Break zurück. Der dadurch neu zugängliche Bereich steht anschließend als Heap-Speicher zur Verfügung.

Das Verfahren ist linear und einfach, kann Speicher in der Mitte jedoch nur schwer zurückgeben. Moderne Allocators bevorzugen mmap für große Anfragen.

void *prev_break = sbrk(0);   /* current break */
sbrk(1024);                   /* grow by 1 KB */
/* prev_break now points to fresh memory */

Block-Metadaten

Für jede Speicheranforderung speichert der Allocator neben den Daten einen kleinen Header: die Größe und die Information, ob der Block frei ist. Dieser Header ermöglicht es free, ausschließlich mit dem Datenzeiger zu arbeiten, den Sie zurückgeben.

Der von malloc empfangene Zeiger zeigt hinter den Header, sodass die Metadaten für Sie verborgen bleiben.

typedef struct block {
    size_t size;
    int free;
    struct block *next;
} block_t;

Zeiger direkt hinter dem Header

Ein verbreiteter Trick ist Zeigerarithmetik: Der Benutzerzeiger ist header + 1. Ausgehend von einem Benutzerzeiger befindet sich der Header um einen block_t davor.

So kann free(p) die Größe des von Ihnen angeforderten Blocks ermitteln, ohne dass Sie sie übergeben müssen.

block_t *hdr = (block_t *)user_ptr - 1;
printf("block size = %zu\n", hdr->size);

Demo für ein kleines Header-Layout

Wir legen einen Header über einen statischen Puffer und lesen ihn wieder aus. Dadurch sehen Sie, wie ein echter Allocator einen Bereich in Header und Nutzdaten aufteilt.

Es sind keine Betriebssystemaufrufe beteiligt, daher läuft das Programm überall.

#include <stdio.h>
#include <stddef.h>

typedef struct { size_t size; int free; } block_t;
static char buffer[256];

int main(void) {
    block_t *h = (block_t *)buffer;
    h->size = 64;
    h->free = 0;
    void *payload = (char *)buffer + sizeof(block_t);
    printf("header bytes = %zu\n", sizeof(block_t));
    printf("payload offset = %ld\n", (long)((char *)payload - buffer));
    printf("size field = %zu\n", h->size);
    return 0;
}

Die Idee der Free List

Viele Allocators verknüpfen freie Blöcke zu einer verketteten Liste. Wenn Sie malloc aufrufen, durchsucht der Allocator diese Liste nach einem ausreichend großen Block.

Beim Aufruf von free wird der Block als frei markiert und für die spätere Wiederverwendung in die Liste zurückgegeben. Dadurch wird eine weitere Anfrage an das Betriebssystem vermieden.

block_t *find_free(block_t *head, size_t size) {
    block_t *b = head;
    while (b && !(b->free && b->size >= size))
        b = b->next;
    return b;
}

Was free tun muss

free(p) findet den Header für p, markiert ihn als frei und führt ihn idealerweise mit angrenzenden freien Blöcken zusammen (Coalescing), um Fragmentierung zu verringern.

Wenn Sie free zweimal für denselben Zeiger aufrufen oder einen Zeiger freigeben, der nicht aus dem Heap stammt, entsteht undefiniertes Verhalten, da die Metadaten beschädigt werden.

void my_free(void *p) {
    if (!p) return;
    block_t *hdr = (block_t *)p - 1;
    hdr->free = 1;
    /* real allocators coalesce neighbors here */
}

Fragmentierung

Wenn im Laufe der Zeit Blöcke unterschiedlicher Größe freigegeben und angefordert werden, entstehen Lücken. Externe Fragmentierung bedeutet, dass zwar freier Speicher vorhanden ist, dieser aber in zu kleine Einzelbereiche verstreut ist, um eine Anfrage zu erfüllen.

Interne Fragmentierung ist ungenutzter Speicher innerhalb eines Blocks, der größer als benötigt ist, häufig aufgrund von Ausrichtung oder Aufrundung.

Ausrichtungsanforderungen

malloc muss Speicher zurückgeben, der für jeden Datentyp korrekt ausgerichtet ist. Auf den meisten 64-Bit-Systemen bedeutet das eine 16-Byte-Ausrichtung, die max_align_t erfüllt.

Fehlende Ausrichtung kann auf manchen CPUs zu Abstürzen führen oder auf anderen den Zugriff verlangsamen. Deshalb runden Allocators Nutzdaten immer auf eine Ausrichtungsgrenze auf.

#include <stdalign.h>
/* alignof(max_align_t) is the strictest required alignment */
size_t a = alignof(max_align_t);

Alles zusammenführen

Ein minimaler Allocator benötigt daher: eine Speicherquelle (statischer Puffer, sbrk oder mmap), Header für jeden Block, eine Strategie zum Auffinden freien Speichers und die Behandlung der Ausrichtung.

In den nächsten Lektionen bauen wir diese Bestandteile auf: zuerst einen Bump-Allocator, dann Free Lists und anschließend Ausrichtung und Blockaufteilung.

/* The four pillars of a custom allocator */
/* 1. memory source   2. block headers */
/* 3. free-block search   4. alignment */

Kurze Überprüfung

Testen Sie Ihr Verständnis der internen Abläufe eines Allocators.

Zusammenfassung

malloc verwaltet einen Heap, den es über sbrk oder mmap vom Betriebssystem erhält, und teilt ihn in Blöcke mit verborgenen Headern auf, die Größe und Freistatus verfolgen.

Free Lists ermöglichen die Wiederverwendung, die Ausrichtung macht den Speicher für jeden Datentyp geeignet, und Fragmentierung ist die zentrale Herausforderung. Diese Ideen bilden die Grundlage für den Allocator, den wir als Nächstes entwickeln.

Häufig gestellte Fragen

Ist die Lektion „Wie malloc funktioniert“ kostenlos?

Ja — der vollständige Text von „Wie malloc funktioniert“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Wie malloc funktioniert“?

Der Heap und Freilisten. Du übst C Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um C Academy zu starten?

Keine Vorkenntnisse erforderlich. C Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.

Wie lange dauert die Lektion „Wie malloc funktioniert“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser C Academy-Lektion Code schreiben und ausführen?

Ja. Jede C Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Wie malloc funktioniert
  2. Ein einfacher Bump-Allocator
  3. Freilisten und Wiederverwendung
  4. Ausrichtung und Aufteilung
← Zurück zu C Academy