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