Kapitel 01: Einführung (Hardware- & Systemsicht)
Dieses Kapitel analysiert Rust aus der Perspektive des Systemprogrammierers. Wir betrachten die Interaktion mit der CPU, dem Arbeitsspeicher und wie der Compiler den Code auf Maschinenebene organisiert.
1. Lernziele
In diesem Abschnitt werden Sie:
- Die physische Repräsentation von Stack und Heap im RAM verstehen.
- Die Funktionsweise des Rust-Compilers bei der Einfügung von Freigabe-Befehlen auf Assembler-Ebene analysieren.
- Die Netzwerk- und File-Watcher-Architektur hinter
mdbook servekennenlernen.
2. Stack vs. Heap auf Hardware-Ebene
Um die Performancegarantien von Rust zu verstehen, müssen wir die Hardware-Architektur betrachten. Ein Prozessor greift auf den Arbeitsspeicher (RAM) über ein hierarchisches Cache-System (L1, L2, L3) zu.
+-------------------------------------------------------+
| CPU |
| +-----------------+ +----------------------------+ |
| | Register (RSP) | | L1/L2 Cache (Cache Lines) | |
| +--------+--------+ +-------------+--------------+ |
+-----------|-------------------------|-----------------+
| (Stack Pointer) | (Cache Hits)
v v
+--------------------+ +-------------------------------+
| Stack (LIFO) | | Heap (RAM) |
| Feste Adressen | | Dynamische Speicherbereiche |
+--------------------+ +-------------------------------+
Der Stack (Stapelspeicher)
- CPU-Register: Der Stack wird direkt über den Stack-Pointer des Prozessors (z. B. das Register
RSPin der x86-64-Architektur) verwaltet. - Allokation: Das Anlegen von Speicherplatz auf dem Stack erfordert lediglich eine einzige CPU-Instruktion: Die Subtraktion eines Offsets vom Stack-Pointer (z. B.
sub rsp, 16). Das Freigeben ist eine Addition (add rsp, 16). - Cache-Lokalität: Da Daten auf dem Stack sequentiell abgelegt werden, befinden sie sich mit hoher Wahrscheinlichkeit in den schnellen L1/L2-Caches der CPU (Cache Line Hits).
Der Heap (Haufenspeicher)
- Allokation: Das Anfordern von Heapspeicher erfordert den Aufruf eines System-Allocators (z. B.
jemallocoderglibc malloc). Dies involviert Systemrufe (System Calls) an den Kernel des Betriebssystems, um freie Speicherseiten (Pages) zu finden. - Latenz: Der Zugriff auf Heap-Daten erfolgt über Pointer. Dies führt häufig zu Cache Misses, da der Prozessor auf das vergleichsweise langsame RAM zugreifen muss, um die tatsächlichen Daten zu lesen.
- Fragmentierung: Häufiges Allokieren und Deallozieren führt zur Fragmentierung des Adressraums.
3. Speicherbereinigung auf Assembler-Ebene
Rust kommt ohne einen Laufzeit-Garbage-Collector aus. Wie wird der Speicher dennoch bereinigt? Der Rust-Compiler analysiert die Scopes statisch und fügt an den Stellen, an denen eine Variable ungültig wird, den entsprechenden Aufruf für den Destruktor (in Rust: Drop-Trait) ein.
Auf Assembler-Ebene sieht dies wie folgt aus:
; Beispiel: Funktion verlässt Gültigkeitsbereich
mov rdi, [rsp+8] ; Lade die Adresse der Heap-Ressource in das Register RDI
call alloc::alloc::dealloc ; Rufe die Deallokationsfunktion des Kernels auf
add rsp, 16 ; Bereinige den Stack-Rahmen
ret ; Kehre zur aufrufenden Funktion zurück
Da diese Aufrufe statisch vom Compiler generiert werden, gibt es keinen Such- oder Scan-Overhead zur Laufzeit. Es entsteht Null-Laufzeit-Overhead (Zero Runtime Overhead).
4. Die Architektur der mdBook Live-Vorschau
Wenn Sie den Befehl mdbook serve ausführen, startet eine mehrteilige Pipeline auf Systemebene:
- File Watcher (OS-Ebene): Das System nutzt Kernel-Subsysteme wie
inotify(unter Linux) oderkqueue(unter macOS), um das Dateiverzeichnischapters/zu überwachen. Diese Systemaufrufe verbrauchen nahezu 0 % CPU-Last im Ruhezustand. - WebSocket-Server: mdBook injiziert ein winziges JavaScript-Snippet in jede generierte HTML-Seite. Dieses Snippet öffnet eine WebSocket-Verbindung (
ws://localhost:3000) zum lokalen mdBook-Server. - Inkrementelles Rendering: Sobald eine Änderung im Dateisystem gemeldet wird, liest mdBook nur die geänderte Datei, generiert das HTML im RAM und sendet ein Broadcast-Signal über das WebSocket-Protokoll an alle verbundenen Browser-Clients, woraufhin diese die Seite per DOM-Reload neu laden.
5. Key Takeaways (Systemebene)
- Stack-Allokation ist extrem schnell und CPU-cachefreundlich (RSP-Register-Manipulation).
- Heap-Allokation erfordert System-Calls und verursacht Latenzen durch Zeiger-Dereferenzierungen.
- Rust deallokiert Speicher durch das statische Einfügen von Destruktor-Aufrufen zur Kompilierzeit direkt in den Assemblercode.