Note
Hinweis: Diese Inhalte wurden mit Unterstützung von Künstlicher Intelligenz erstellt und redaktionell überprüft (Transparenzhinweis gemäß Art. 50 EU AI Act).
Kapitel 01b: Der 8-Wochen-Trainingsplan (Hardware- & Systemsicht)
Dieser Plan analysiert die wöchentlichen Konzepte aus der Perspektive der CPU-Architektur, des Speicherlayouts (Stack & Heap) und des vom Compiler generierten Maschinencodes.
Woche 1: Register, Stack-Belegung & Alignments (Kapitel 01 - 03)
- Hardware-Prozess: Lokale Variablen werden auf dem Stack angeordnet. Der Compiler berechnet das exakte Speicher-Alignment für jeden primitiven Typ (z.B. müssen 32-Bit Integers auf Adressen allokiert werden, die durch 4 teilbar sind).
- Was im RAM passiert:
Shadowing belegt physisch keinen neuen RAM-Speicher, wenn die Lebensdauer der überschatteten Variable endet. Der Compiler optimiert die Registerbelegung (
RAX,RCXetc.) so, dass unnötige Stack-Schreibzugriffe minimiert werden. - Compilerfehler (Hardware-Perspektive):
Umgang mit Integer-Overflows. Im Debug-Modus fügt Rust Checks ein, die bei einem Overflow ein Signal an die CPU senden, um das Programm kontrolliert abzubrechen (
panic). Im Release-Modus (Opt-Level 3) wird standardmäßig das hardwareseitige Wrap-Around-Verhalten der CPU genutzt.
Woche 2: Speicherfreigabe ohne Garbage Collector (Kapitel 04 & 05)
- Hardware-Prozess:
Beim Verlassen eines Scopes fügt der Compiler den Destruktor-Aufruf (
drop) direkt in den Assemblercode ein. Heap-Speicher wird über einen System-Allocator (z.B. jemalloc oder den Standard-OS-Allocator) freigegeben. - Was im RAM passiert:
Ein
Stringbelegt auf dem Stack exakt 24 Bytes (64-Bit-System): 8 Bytes Pointer auf den Heap-Speicher, 8 Bytes Kapazität und 8 Bytes Länge. EinMovekopiert lediglich diese 24 Bytes auf dem Stack – die Heap-Daten werden nicht angefasst. - Compilerfehler (Hardware-Perspektive): Verhinderung von Dangling Pointers. Der Borrow Checker verhindert statisch, dass ein Zeiger auf dem Stack auf eine Speicheradresse verweist, die bereits freigegeben wurde.
Woche 3: Cache-Lokalität & Struct-Layouts (Kapitel 06 & 10)
- Hardware-Prozess:
Vektoren (
Vec<T>) liegen als zusammenhängendes Array im Heap. Dies sorgt für eine exzellente Cache-Lokalität (L1/L2-Caches), da die CPU bei einem Zugriff nachfolgende Daten bereits in einer Cache-Line (typischerweise 64 Bytes) vorlädt. - Was im RAM passiert:
Rust ordnet die Felder eines Structs im Speicher so an, dass Padding (Leerplatz zur Einhaltung des Alignments) minimiert wird. Der Compiler darf die Reihenfolge der Felder im RAM verändern (im Gegensatz zu C, wo die Deklarationsreihenfolge strikt eingehalten werden muss), es sei denn, man erzwingt dies über
#[repr(C)]. - Compilerfehler (Hardware-Perspektive):
Die Übergabe von
selfper Wert an eine Methode kopiert die Strukturdaten auf dem Stack. Große Strukturen sollten daher per Referenz (&self) übergeben werden, um CPU-Kopierzyklen zu vermeiden.
Woche 4: Stack Frames & Closure-Inlining (Kapitel 07 & 09)
- Hardware-Prozess: Funktionsaufrufe erzeugen Stack Frames. Rust optimiert diese durch Inlining: Kurze Funktionen werden direkt an der Aufrufstelle eingesetzt, wodurch der Call-Overhead (Push des Instruction Pointers auf den Stack, Sprung, Pop) komplett entfällt.
- Was im RAM passiert: Closures, die keine Variablen einfangen, werden als normale Funktionszeiger repräsentiert. Closures, die Variablen einfangen, werden vom Compiler in anonyme Structs übersetzt, die die eingefangenen Variablen als Felder halten (entweder als Referenzen oder als Werte).
- Compilerfehler (Hardware-Perspektive): Vermeidung von Stack Overflows durch unendliche Rekursion. Der Compiler warnt vor rekursiven Aufrufen, die den Stack-Speicher (standardmäßig 2 MB für Threads unter Linux) aufbrauchen würden.
Woche 5: Bitmuster von Enums & Branch Prediction (Kapitel 08 & 12)
- Hardware-Prozess: Enums werden im Speicher als Tagged Unions dargestellt. Sie bestehen aus einem Diskriminator-Byte (Tag, welcher anzeigt, welche Variante aktiv ist) und dem Payload der größten Variante.
- Was im RAM passiert:
Durch die Null-Pointer-Optimierung belegt
Option<&T>exakt so viel Platz wie ein roher Zeiger (8 Bytes). Da ein Referenzzeiger niemals null sein darf, nutzt der Compiler das Bitmuster0x0zur Darstellung der VarianteNone. - Compilerfehler (Hardware-Perspektive): Große Enums in match-Blöcken können zu vielen Sprungbefehlen führen. Der Compiler versucht, diese in hocheffiziente Sprungtabellen (Jump Tables) im Maschinencode zu übersetzen, um die Branch Prediction der CPU optimal zu nutzen.
Woche 6: Monomorphisierung & vtables (Kapitel 11, 13 & 14)
- Hardware-Prozess: Generics in Rust werden durch Monomorphisierung aufgelöst. Für jede genutzte Typkombination generiert der Compiler eine eigene Kopie der Funktion im Maschinencode.
- Was im RAM passiert:
- Statischer Dispatch (
impl Trait): Direkter Funktionsaufruf im Maschinencode. Kein Laufzeit-Overhead, aber größeres Binärfile (Instruction Cache Belastung). - Dynamischer Dispatch (
dyn Trait): Der Aufruf erfolgt über einen Fat Pointer. Dieser enthält den Datenzeiger und einen Zeiger auf die vtable (Virtual Method Table). Das Laden der Funktionsadresse aus der vtable kostet eine Speicherindirektion.
- Statischer Dispatch (
- Compilerfehler (Hardware-Perspektive): Monomorphisierungs-Fehler entstehen, wenn generische Typen die Trait Bounds nicht erfüllen. Dies verhindert, dass der Compiler den Maschinencode für diesen spezifischen Typ korrekt generieren kann.
Woche 7: Thread Scheduling & Cache-Kohärenz (Kapitel 15 & 16)
- Hardware-Prozess:
std::thread::spawnerzeugt einen echten OS-Thread, der vom Scheduler des Betriebssystems auf den CPU-Kernen verteilt wird. - Was im RAM passiert:
Beim Zugriff auf geteilte Daten über
Mutexmüssen die CPU-Kerne ihre L1-Caches synchronisieren (Cache-Kohärenz-Protokolle wie MESI). EinMutexnutzt atomare CPU-Befehle (z.B. Compare-And-Swap / CAS), um den Lock-Zustand threadsicher abzufragen und zu verändern, ohne in den Kernel-Modus wechseln zu müssen (Futex unter Linux). - Compilerfehler (Hardware-Perspektive):
Data Races entstehen, wenn zwei CPU-Kerne ohne Synchronisation auf dieselbe Speicheradresse zugreifen und mindestens einer schreibt. Rust verhindert dies, indem es den Zugriff nur erlaubt, wenn die Typen den
Send- undSync-Trait implementieren.
Woche 8: Rohe Zeiger & LLVM-Optimierungen (Kapitel 17 - 20)
- Hardware-Prozess:
Rohe Zeiger (
*const T,*mut T) sind einfache 64-Bit-Speicheradressen ohne jegliche Sicherheitsprüfung durch die CPU oder den Compiler. - Was im RAM passiert:
Im
unsafe-Block umgehen Sie den Borrow Checker. Sie können direkt auf Register zugreifen, Memory-Mapped I/O (MMIO) durchführen oder Speicher direkt allokieren. Der LLVM-Optimizer analysiert Ihren Code und wendet aggressive Optimierungen wie Loop Unrolling, Vectorization (SIMD) und Dead Code Elimination an. - Compilerfehler (Hardware-Perspektive): Ein Absturz in Unsafe Rust (z.B. ein Segmentierungsfehler / Segmentation Fault) wird durch einen ungültigen Speicherzugriff auf CPU-Ebene ausgelöst (z.B. Zugriff auf geschützten Kernel-Speicher). Der Compiler kann dies im Vorfeld nicht abfangen.
Note
Hinweis: Diese Inhalte wurden mit Unterstützung von Künstlicher Intelligenz erstellt und redaktionell überprüft (Transparenzhinweis gemäß Art. 50 EU AI Act).