0Pricing
Swift Academy · Lezione

MemoryLayout e allineamento

Ispezioni dimensione, stride e allineamento dei tipi.

MemoryLayout e allineamento è una lezione Swift Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Swift Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Swift Academy include 4 lezioni in totale.

Perché il layout della memoria è importante

Quando lavora con unsafe Swift o interopera con C, deve sapere come sono disposti i valori in memoria. Swift mette a disposizione MemoryLayout<T> per esaminare questo aspetto senza toccare direttamente i byte grezzi.

Risponde a tre domande: quanto è grande un valore, qual è la distanza tra i valori in un array e su quale limite di indirizzo deve iniziare un valore.

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

size — Memorizzazione effettiva

MemoryLayout<T>.size indica il numero di byte occupati dai dati significativi del valore. Non include il padding finale che può trovarsi tra gli elementi di un array.

Utilizzi size quando desidera sapere quanti byte significativi contiene un singolo valore.

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

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

stride — Spaziatura negli array

stride è la distanza in byte tra l'inizio di un elemento e quello dell'elemento successivo quando i valori sono disposti in un array contiguo. È uguale a size arrotondato in base all'allineamento.

Quando alloca manualmente i buffer, moltiplichi per stride, mai per size.

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

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

alignment — Limiti degli indirizzi

alignment è il limite di byte su cui deve iniziare un valore. Un Int64 con alignment pari a 8 deve iniziare a un indirizzo divisibile per 8. Il compilatore inserisce padding per rispettare questo vincolo.

L'allineamento di una struct è il maggiore tra gli allineamenti dei suoi membri.

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

La differenza tra size e stride

Per molti tipi size == stride, ma i due valori divergono quando è presente del padding. Una struct può avere size pari a 9 e stride pari a 16 perché l'elemento successivo deve essere allineato su 8 byte.

Regola pratica: ragioni sul singolo valore con size e sulle raccolte con stride.

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

Offset dei campi

Per le struct può chiedere dove si trova ogni proprietà memorizzata rispetto all'inizio, usando MemoryLayout<T>.offset(of:) con un key path. È essenziale quando dispone i dati in modo compatibile con una struct C.

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

Riordinare per risparmiare spazio

A causa dell'allineamento, l'ordine delle proprietà memorizzate influisce sulle dimensioni. Posizionare prima i campi più grandi o raggrupparli in base alle dimensioni può ridurre le dimensioni di una struct. Questo è importante per gli array grandi, in cui i byte sprecati si accumulano.

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 dei riferimenti

Un'istanza di classe viene allocata nell'heap, quindi una variabile che contiene un riferimento a una classe è semplicemente un pointer. Il suo MemoryLayout.size corrisponde alla dimensione del puntatore (8 byte), indipendentemente dalle dimensioni dell'oggetto.

I tipi valore, come le struct, memorizzano il contenuto inline; i tipi riferimento memorizzano solo il puntatore.

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

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

Optional ed enumerazioni

Gli optional di solito aggiungono un byte per il tag, ma Swift ottimizza gli optional di reference riutilizzando il puntatore nullo, quindi String? può avere le stesse dimensioni di String.

Le enumerazioni con valori associati hanno dimensioni sufficienti a contenere il caso più grande e un discriminatore.

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

Usare of: con un'istanza

Ogni membro (size, stride, alignment) dispone anche di una forma basata sull'istanza: MemoryLayout.size(ofValue:). È utile quando è difficile specificare il tipo o quando questo viene dedotto.

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

Allocare con il layout corretto

Quando alloca memoria grezza deve specificare sia il numero di byte sia l'allineamento. Recuperare questi valori da MemoryLayout garantisce la correttezza su architetture diverse, invece di usare numeri codificati manualmente.

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() }

Verifica rapida

Metta alla prova la Sua comprensione della differenza tra size e stride.

Riepilogo

Ha imparato i tre pilastri del layout della memoria:

  • size — byte significativi di un singolo valore
  • stride — spaziatura tra gli elementi di un array, da usare per l'allocazione
  • alignment — limite di inizio richiesto

Ha inoltre visto offset(of:) per la posizione dei campi, come l'ordine delle proprietà influisca sulle dimensioni e che i riferimenti hanno semplicemente le dimensioni di un puntatore. Questi strumenti consentono di allocare e interpretare la memoria grezza in modo sicuro.

Domande Frequenti

La lezione «MemoryLayout e allineamento» è gratuita?

Sì — il testo completo di «MemoryLayout e allineamento» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Swift Academy, passa a CoddyKit PRO. Il corso Swift Academy include 4 lezioni in totale.

Cosa imparerò in «MemoryLayout e allineamento»?

Ispezioni dimensione, stride e allineamento dei tipi. Eserciti Swift Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Swift Academy?

Non è richiesta alcuna esperienza precedente. Swift Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «MemoryLayout e allineamento»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Swift Academy?

Sì. Ogni lezione Swift Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. MemoryLayout e allineamento
  2. UnsafePointer e UnsafeMutablePointer
  3. Puntatori buffer non sicuri
  4. withUnsafeBytes e interoperabilità con C
← Torna a Swift Academy