std.mmap_ext

Erweiterte Memory-Operationen (WP-9): Ergänzt das Basis-mmap/munmap um Größenänderung (mremap), Zugriffshinweise an den Kernel (madvise), Synchronisierung memory-gemappter Dateien (msync), In-Memory-Dateien ohne Filesystem (memfd_create), RAM-Pinning (mlock) und Residency-Prüfung (mincore).

Standard Library · std.alloc · std.fs_ext


Konstanten

madvise-Hinweise

Konstante Wert Beschreibung
MADV_NORMAL 0 Standard-Verhalten, keine Optimierung
MADV_RANDOM 1 Zufälliger Zugriff — Prefetching deaktivieren
MADV_SEQUENTIAL 2 Sequenzieller Zugriff — aggressives Prefetching
MADV_WILLNEED 3 Seiten werden bald benötigt — im Voraus einlesen
MADV_DONTNEED 4 Seiten werden nicht mehr benötigt — physikalischen RAM freigeben
MADV_FREE 8 Seiten dürfen freigegeben werden (lazy — erst bei Speicherdruck)
MADV_REMOVE 9 Bereich aus Backing-Store entfernen (tmpfs/shmem)
MADV_HUGEPAGE 14 Transparent Huge Pages für diesen Bereich aktivieren
MADV_NOHUGEPAGE 15 Transparent Huge Pages deaktivieren
MADV_COLD 20 Seiten als kalt markieren — werden bei Speicherdruck zuerst ausgelagert
MADV_PAGEOUT 21 Seiten sofort auslagern

msync-Flags

Konstante Wert Beschreibung
MS_ASYNC 1 Synchronisierung im Hintergrund starten
MS_SYNC 4 Blockierend warten bis Daten auf Disk geschrieben sind
MS_INVALIDATE 2 Andere Mappings derselben Datei invalidieren

mremap-Flags

Konstante Wert Beschreibung
MREMAP_MAYMOVE 1 Kernel darf den Bereich verschieben wenn nötig
MREMAP_FIXED 2 Mapping auf feste Zieladresse erzwingen
MREMAP_DONTUNMAP 4 Altes Mapping beibehalten (Kernel 5.7+)

memfd_create-Flags

Konstante Wert Beschreibung
MFD_CLOEXEC 1 fd bei exec() schließen
MFD_ALLOW_SEALING 2 Sealing-Operationen erlauben (fcntl F_ADD_SEALS)
MFD_HUGETLB 4 Mapping mit Huge Pages

Sonstiges

Weitere Hilfsfunktionen:

Konstante Wert Beschreibung
PAGE_SIZE 4096 Seitengröße auf x86-64 Linux in Bytes

Funktionen

Mapping-Größe ändern

Signatur Beschreibung
MmapResize(addr: int64, oldSize: int64, newSize: int64): int64 Ändert die Größe eines bestehenden Mappings. Der Kernel darf es verschieben (MREMAP_MAYMOVE). Gibt die neue Adresse zurück — diese kann sich gegenüber addr ändern!
MmapResizeFixed(addr: int64, oldSize: int64, newSize: int64, newAddr: int64): int64 Wie MmapResize, verschiebt aber auf eine feste Zieladresse newAddr

Zugriffshinweise

Signatur Beschreibung
MmapAdvise(addr: int64, len: int64, advice: int64): int64 Gibt dem Kernel einen Hinweis über das geplante Zugriffsverhalten (MADV_*). Gibt 0 bei Erfolg
MmapFreePages(addr: int64, len: int64): int64 Gibt physikalische Seiten zurück ohne das Mapping zu entfernen (MADV_DONTNEED). Nächster Zugriff liefert nullisierte Seiten

Datei-Mapping synchronisieren

Signatur Beschreibung
MmapSync(addr: int64, len: int64, flags: int64): int64 Schreibt Änderungen am Mapping in die zugrunde liegende Datei zurück. MS_SYNC = blockierend, MS_ASYNC = im Hintergrund. Auf anonymen Mappings ist dies ein No-Op

In-Memory-Datei

Signatur Beschreibung
MemFdCreate(name: pchar, flags: int64): int64 Erstellt eine anonyme In-Memory-Datei. name ist ein Debug-Name (sichtbar in /proc/pid/fd). Danach ftruncate + mmap für Shared Memory ohne Filesystem. Gibt fd zurück

RAM-Pinning

Signatur Beschreibung
MemLock(addr: int64, len: int64): int64 Sperrt die Seiten im RAM — kein Swapping. Erfordert CAP_IPC_LOCK oder genug RLIMIT_MEMLOCK-Budget
MemUnlock(addr: int64, len: int64): int64 Hebt die RAM-Sperre auf — Seiten dürfen wieder ausgelagert werden

Residency-Prüfung

Signatur Beschreibung
MemInCore(addr: int64, len: int64, vecOut: int64): int64 Füllt vecOut mit dem Residency-Status: Ein Byte pro Seite, Bit 0 = 1 → Seite ist im RAM. vecOut: alloc(ceil(len / PAGE_SIZE))
MemIsResident(addr: int64): bool Gibt true zurück wenn die erste Seite an addr aktuell im RAM ist

Verwendung

Wachsender Puffer via mremap

import std.mmap_ext;
import std.alloc;

// mmap-basierter Puffer der ohne Kopie wachsen kann.
fn GrowBuffer(addr: int64, oldSize: int64, newSize: int64): int64 {
    var newAddr := MmapResize(addr, oldSize, newSize);
    if (newAddr < 0) { return -1; }
    // WICHTIG: newAddr kann != addr sein — alten Pointer nicht mehr verwenden!
    return newAddr;
}

Sequential Read: Prefetching aktivieren

import std.mmap_ext;

fn ProcessLargeFile(addr: int64, size: int64): void {
    // Kernel wird Seiten aggressiv prefetchen
    MmapAdvise(addr, size, MADV_SEQUENTIAL);

    // Nach dem Verarbeiten: physikalischen RAM freigeben
    MmapFreePages(addr, size);
}

Shared Memory via memfd_create

import std.mmap_ext;
import std.fs_ext;
import std.io;

fn CreateSharedMem(size: int64): int64 {
    var fd := MemFdCreate("shm_worker", MFD_CLOEXEC);
    if (fd < 0) { return -1; }

    // Größe festlegen
    Ftruncate(fd, size);

    // Mapping erstellen (PROT_READ|WRITE = 3, MAP_SHARED = 1)
    var addr := mmap(0, size, 3, 1, fd, 0);
    close(fd);   // fd kann nach mmap geschlossen werden
    return addr;
}

Latenz-kritischer Code: Seiten im RAM fixieren

import std.mmap_ext;
import std.alloc;

fn LockCriticalBuffer(size: int64): int64 {
    // size muss Vielfaches von PAGE_SIZE sein
    var addr := mmap(0, size, 3, 34, -1, 0);  // PROT_RW, MAP_PRIVATE|ANON
    if (addr < 0) { return -1; }

    // Seiten vorwärts anfassen (erzwingt Seitenzuteilung)
    MmapAdvise(addr, size, MADV_WILLNEED);

    // RAM fixieren — kein Swapping mehr
    MemLock(addr, size);

    return addr;
}

fn UnlockAndFree(addr: int64, size: int64): void {
    MemUnlock(addr, size);
    munmap(addr, size);
}

Prüfen welche Seiten im RAM sind

import std.mmap_ext;
import std.alloc;
import std.io;

fn PrintResidency(addr: int64, size: int64): void {
    var pages  := (size + PAGE_SIZE - 1) / PAGE_SIZE;
    var vecOut := alloc(pages);

    MemInCore(addr, size, vecOut);

    var inRam: int64 := 0;
    var i: int64 := 0;
    while (i < pages) {
        if ((peek8(vecOut + i) & 1) != 0) { inRam := inRam + 1; }
        i := i + 1;
    }

    PrintLn("Seiten im RAM: " + IntToStr(inRam) + " / " + IntToStr(pages));

    free(vecOut, pages);
}


Hinweise

  • MmapResize gibt eine neue Adresse zurück — den alten Zeiger danach nicht mehr dereferenzieren.
  • MmapFreePages (MADV_DONTNEED) gibt nur physikalischen RAM frei; das virtuelle Mapping bleibt erhalten und wird beim nächsten Zugriff mit Nullen neu befüllt.
  • MFD_ALLOW_SEALING ermöglicht es, nach dem Befüllen das Mapping read-only zu versiegeln — nützlich für unveränderliche Shared-Memory-Objekte.
  • MemLock schlägt mit -ENOMEM fehl wenn das Prozess-Limit (RLIMIT_MEMLOCK) erreicht ist; Root hat standardmäßig kein Limit.
  • addr und len müssen bei allen Funktionen auf PAGE_SIZE (4096) ausgerichtet sein.

Verwandte Units

  • std.alloc — Basis-Speicherverwaltung (mmap/munmap-basiert)
  • std.fs_ext — Fstat, Ftruncate (für memfd-Workflow)
  • std.fs — Dateizugriff für dateibasierte Mappings
  • std.sched — CPU-Affinität (ergänzt RAM-Pinning bei Echtzeit-Anforderungen)

Letzte Aktualisierung: 2026-06-05