0Pricing
Swift Academy · Lektion

MemoryLayout und Ausrichtung

Untersuchen Sie Größe, stride und Ausrichtung von Typen.

MemoryLayout und Ausrichtung ist eine kostenlose Swift 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 Swift Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Swift Academy-Kurs umfasst insgesamt 4 Lektionen.

Warum das Speicherlayout wichtig ist

Wenn Sie mit unsafe Swift arbeiten oder eine Verbindung zu C herstellen, müssen Sie wissen, wie Werte im Speicher angeordnet sind. Swift stellt Ihnen MemoryLayout<T> zur Verfügung, um dies zu untersuchen, ohne jemals rohe Bytes anzufassen.

Es beantwortet drei Fragen: Wie groß ist ein Wert, wie weit liegen Werte in einem Array auseinander und an welcher Adressgrenze muss ein Wert beginnen?

// MemoryLayout works on any type
print(MemoryLayout<Int>.size)       // 8 on 64-bit
print(MemoryLayout<Bool>.size)      // 1
print(MemoryLayout<Double>.size)    // 8

size — Tatsächlicher Speicherbedarf

MemoryLayout<T>.size gibt die Anzahl der Bytes an, die die relevanten Daten eines Werts belegen. Nachfolgende Auffüllbytes, die zwischen Elementen eines Arrays liegen können, sind darin nicht enthalten.

Verwenden Sie size, wenn Sie wissen möchten, wie viele relevante Bytes ein einzelner Wert belegt.

struct Point {
    var x: Int8   // 1 byte
    var y: Int64  // 8 bytes
}

print(MemoryLayout<Point>.size)   // 16 (not 9 — padding!)

stride — Abstand in Arrays

stride ist der Abstand in Bytes zwischen dem Anfang eines Elements und dem Anfang des nächsten, wenn Werte in einem zusammenhängenden Array angeordnet sind. Der Wert entspricht size, auf die Ausrichtung aufgerundet.

Wenn Sie Puffer manuell allokieren, multiplizieren Sie immer mit stride, niemals mit size.

print(MemoryLayout<Point>.stride) // 16
print(MemoryLayout<Int8>.stride)  // 1

// Buffer for 10 Points needs:
let bytes = 10 * MemoryLayout<Point>.stride // 160

alignment — Adressgrenzen

alignment ist die Byte-Grenze, an der ein Wert beginnen muss. Ein Int64 mit einer Ausrichtung von 8 muss an einer Adresse beginnen, die durch 8 teilbar ist. Der Compiler fügt Auffüllbytes ein, um dies sicherzustellen.

Die Ausrichtung einer Struktur entspricht der größten Ausrichtung ihrer Mitglieder.

print(MemoryLayout<Int8>.alignment)   // 1
print(MemoryLayout<Int64>.alignment)  // 8
print(MemoryLayout<Point>.alignment)  // 8

Der Unterschied zwischen size und stride

Für viele Typen gilt size == stride, aber sobald Auffüllbytes vorhanden sind, unterscheiden sich die beiden Werte. Eine Struktur kann eine size von 9, aber eine stride von 16 haben, weil das nächste Element an einer 8-Byte-Grenze ausgerichtet sein muss.

Faustregel: Verwenden Sie size, wenn Sie einen einzelnen Wert betrachten, und stride, wenn Sie über Sammlungen nachdenken.

struct Mixed {
    var flag: Bool   // 1
    var value: Int   // 8
}
print(MemoryLayout<Mixed>.size)   // 16
print(MemoryLayout<Mixed>.stride) // 16

Feld-Offsets

Bei Strukturen können Sie mit MemoryLayout<T>.offset(of:) und einem Key Path abfragen, wo sich jede gespeicherte Eigenschaft relativ zum Anfang befindet. Das ist unerlässlich, wenn Sie Daten passend zu einer C-Struktur anordnen.

struct Header {
    var magic: UInt32  // offset 0
    var length: UInt64 // offset 8 (padded)
}

print(MemoryLayout<Header>.offset(of: \Header.magic) ?? -1)  // 0
print(MemoryLayout<Header>.offset(of: \Header.length) ?? -1) // 8

Neuordnung zum Platzsparen

Da die Ausrichtung berücksichtigt werden muss, beeinflusst die Reihenfolge gespeicherter Eigenschaften die Größe. Wenn Sie größere Felder zuerst platzieren oder Felder nach ihrer Größe gruppieren, kann eine Struktur kleiner werden. Das ist bei großen Arrays wichtig, weil sich ungenutzte Bytes summieren.

struct Wasteful { var a: Int8; var b: Int64; var c: Int8 } // size 24
struct Tight    { var b: Int64; var a: Int8; var c: Int8 } // size 16

print(MemoryLayout<Wasteful>.size)
print(MemoryLayout<Tight>.size)

Layout von Referenzen

Eine Klasseninstanz wird auf dem Heap allokiert. Eine Variable, die eine Klassenreferenz enthält, ist daher nur ein Zeiger. Ihre MemoryLayout.size entspricht unabhängig von der Größe des Objekts der Zeigergröße, also 8 Bytes.

Wertetypen wie Strukturen speichern ihre Inhalte inline; Referenztypen speichern nur den Zeiger.

class Big { var data = [Int](repeating: 0, count: 1000) }

print(MemoryLayout<Big>.size) // 8 — just the reference

Optionals und Enums

Optionals fügen normalerweise ein Byte für das Tag hinzu. Swift optimiert jedoch Referenz-Optionals, indem der Nullzeiger wiederverwendet wird, sodass String? dieselbe Größe wie String haben kann.

Enums mit zugehörigen Werten werden so groß angelegt, dass sie ihren größten Fall zuzüglich eines Unterscheidungswerts aufnehmen können.

print(MemoryLayout<Int?>.size)    // 9
print(MemoryLayout<String>.size)  // 16
print(MemoryLayout<String?>.size) // 16 — no extra byte

of: mit einer Instanz verwenden

Jedes Mitglied (size, stride, alignment) besitzt auch eine instanzbasierte Form: MemoryLayout.size(ofValue:). Das ist praktisch, wenn sich der Typ nur schwer ausschreiben lässt oder vom Compiler hergeleitet wird.

let tuple = (UInt8(1), UInt64(2))
print(MemoryLayout.size(ofValue: tuple))      // 16
print(MemoryLayout.stride(ofValue: tuple))    // 16
print(MemoryLayout.alignment(ofValue: tuple)) // 8

Mit dem richtigen Layout allokieren

Wenn Sie rohen Speicher allokieren, müssen Sie sowohl die Byte-Anzahl als auch die Ausrichtung übergeben. Wenn Sie diese Werte aus MemoryLayout beziehen, ist die Korrektheit auf verschiedenen Architekturen gewährleistet, anstatt Zahlen fest zu codieren.

let count = 4
let capacity = count * MemoryLayout<Int>.stride
let align = MemoryLayout<Int>.alignment

let raw = UnsafeMutableRawPointer.allocate(
    byteCount: capacity, alignment: align)
defer { raw.deallocate() }

Kurze Überprüfung

Testen Sie Ihr Verständnis des Unterschieds zwischen size und stride.

Zusammenfassung

Sie haben die drei Grundlagen des Speicherlayouts kennengelernt:

  • size — relevante Bytes eines einzelnen Werts
  • stride — Abstand zwischen Array-Elementen (bei der Allokation zu verwenden)
  • alignment — erforderliche Startgrenze

Außerdem haben Sie offset(of:) für die Positionen von Feldern, den Einfluss der Eigenschaftsreihenfolge auf die Größe und die Tatsache kennengelernt, dass Referenzen lediglich die Größe eines Zeigers haben. Mit diesen Werkzeugen können Sie rohen Speicher sicher allokieren und interpretieren.

Häufig gestellte Fragen

Ist die Lektion „MemoryLayout und Ausrichtung“ kostenlos?

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

Was lerne ich in „MemoryLayout und Ausrichtung“?

Untersuchen Sie Größe, stride und Ausrichtung von Typen. Du übst Swift 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 Swift Academy zu starten?

Keine Vorkenntnisse erforderlich. Swift 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 „MemoryLayout und Ausrichtung“?

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 Swift Academy-Lektion Code schreiben und ausführen?

Ja. Jede Swift 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. MemoryLayout und Ausrichtung
  2. UnsafePointer und UnsafeMutablePointer
  3. Unsichere Buffer-Pointer
  4. withUnsafeBytes und C-Interop
← Zurück zu Swift Academy