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) // 8size — 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 // 160alignment — 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) // 8La 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) // 16Offset 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) // 8Riordinare 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 referenceOptional 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 byteUsare 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)) // 8Allocare 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
- MemoryLayout e allineamento
- UnsafePointer e UnsafeMutablePointer
- Puntatori buffer non sicuri
- withUnsafeBytes e interoperabilità con C