MemoryLayout ja kohdistus
Tutki tyyppien koon, stride-arvon ja kohdistuksen.
MemoryLayout ja kohdistus on ilmainen Swift Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Swift Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Swift Academy-kurssilla on yhteensä 4 oppituntia.
Miksi muistin asettelulla on merkitystä
Kun työskentelet unsafe Swift -koodin parissa tai yhdistät koodia C:hen, sinun on tunnettava, miten arvot on järjestetty muistiin. Swift tarjoaa MemoryLayout<T>-tyypin tämän tutkimiseen ilman, että käsittelet raakatavuja.
Se vastaa kolmeen kysymykseen: kuinka paljon tilaa arvo vie, kuinka kaukana arvot ovat toisistaan taulukossa ja millä osoiterajalla arvon on alettava.
// MemoryLayout works on any type
print(MemoryLayout<Int>.size) // 8 on 64-bit
print(MemoryLayout<Bool>.size) // 1
print(MemoryLayout<Double>.size) // 8size — Todellinen tallennustila
MemoryLayout<T>.size on niiden tavujen määrä, jotka arvon merkityksellinen data vie. Se ei sisällä loppuun lisättyä täytettä, jota elementtien välissä voi olla taulukossa.
Käytä size-ominaisuutta, kun haluat tietää, kuinka monta merkityksellistä tavua yksittäinen arvo sisältää.
struct Point {
var x: Int8 // 1 byte
var y: Int64 // 8 bytes
}
print(MemoryLayout<Point>.size) // 16 (not 9 — padding!)stride — Taulukoiden välinen tila
stride on tavuina ilmaistu etäisyys yhden elementin alusta seuraavan elementin alkuun, kun arvot on pakattu yhtenäiseen taulukkoon. Se on size-arvo pyöristettynä ylöspäin kohdistuksen mukaiseksi.
Kun varaat puskureita käsin, kerro aina stride-arvolla, älä koskaan size-arvolla.
print(MemoryLayout<Point>.stride) // 16
print(MemoryLayout<Int8>.stride) // 1
// Buffer for 10 Points needs:
let bytes = 10 * MemoryLayout<Point>.stride // 160alignment — Osoiterajat
alignment on tavuina ilmaistu raja, jolta arvon on alettava. Kohdistuksen 8 omaavan Int64-arvon on alettava osoitteesta, joka on jaollinen luvulla 8. Kääntäjä lisää täytettä tämän varmistamiseksi.
Rakenteen kohdistus on sen jäsenten suurin kohdistus.
print(MemoryLayout<Int8>.alignment) // 1
print(MemoryLayout<Int64>.alignment) // 8
print(MemoryLayout<Point>.alignment) // 8size- ja stride-arvojen ero
Monilla tyypeillä size == stride, mutta arvot eroavat toisistaan aina, kun mukana on täytettä. Rakenteen size voi olla 9 ja stride 16, koska seuraavan elementin on oltava 8 tavun rajalla.
Nyrkkisääntö: tarkastele yksittäistä arvoa size-arvon avulla ja kokoelmia stride-arvon avulla.
struct Mixed {
var flag: Bool // 1
var value: Int // 8
}
print(MemoryLayout<Mixed>.size) // 16
print(MemoryLayout<Mixed>.stride) // 16Kenttien siirtymät
Rakenteilta voi kysyä, missä kukin tallennettu ominaisuus sijaitsee suhteessa alkuun käyttämällä MemoryLayout<T>.offset(of:)-metodia key pathin kanssa. Tämä on olennaista, kun data on aseteltava C-rakenteen kanssa yhteensopivaksi.
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) // 8Uudelleenjärjestäminen tilan säästämiseksi
Kohdistuksen vuoksi tallennettujen ominaisuuksien järjestys vaikuttaa kokoon. Suurempien kenttien sijoittaminen ensin tai kenttien ryhmittely koon mukaan voi pienentää rakennetta. Tämä on tärkeää suurissa taulukoissa, joissa hukkaan menevät tavut kasautuvat.
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)Viitteiden asettelu
Luokan ilmentymä varataan keosta, joten luokkaviitettä sisältävä muuttuja on vain osoitin. Sen MemoryLayout.size on osoittimen koko eli 8 tavua objektin koosta riippumatta.
Arvotyypit, kuten rakenteet, tallentavat sisältönsä suoraan; viitetyypit tallentavat vain osoittimen.
class Big { var data = [Int](repeating: 0, count: 1000) }
print(MemoryLayout<Big>.size) // 8 — just the referenceOptionalit ja enumeraatiot
Optionalit lisäävät yleensä tavun tunnistetta varten, mutta Swift optimoi viite-optionalit käyttämällä null-osoitinta uudelleen, joten String? voi olla samankokoinen kuin String.
Liittyviä arvoja sisältävien enumeraatioiden koko riittää suurimman tapauksen ja erottimen tallentamiseen.
print(MemoryLayout<Int?>.size) // 9
print(MemoryLayout<String>.size) // 16
print(MemoryLayout<String?>.size) // 16 — no extra byteof:-metodin käyttö ilmentymän kanssa
Jokaisella jäsenellä (size, stride, alignment) on myös ilmentymään perustuva muoto: MemoryLayout.size(ofValue:). Tämä on kätevää, kun tyyppiä on vaikea kirjoittaa tarkasti tai se päätellään automaattisesti.
let tuple = (UInt8(1), UInt64(2))
print(MemoryLayout.size(ofValue: tuple)) // 16
print(MemoryLayout.stride(ofValue: tuple)) // 16
print(MemoryLayout.alignment(ofValue: tuple)) // 8Varaaminen oikean asettelun mukaan
Kun varaat raakamuistia, sinun on annettava sekä tavumäärä että kohdistus. Kun haet nämä arvot MemoryLayout-tyypistä, toimivuus säilyy eri arkkitehtuureilla sen sijaan, että koodiin kirjoitettaisiin kiinteitä lukuja.
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() }Pikatarkistus
Testaa, miten ymmärrät size- ja stride-arvojen eron.
Kertaus
Opit muistin asettelun kolme peruspilaria:
- size — yksittäisen arvon merkitykselliset tavut
- stride — taulukon elementtien välinen tila, jota käytetään varaamiseen
- alignment — vaadittu aloitusraja
Näet myös, miten offset(of:) ilmoittaa kenttien sijainnit, miten ominaisuuksien järjestys vaikuttaa kokoon ja että viitteet ovat vain osoittimen kokoisia. Näiden työkalujen avulla voit varata ja tulkita raakamuistia turvallisesti.
Opi Swift tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 122
- Oppitunnit
- 409
Usein kysytyt kysymykset
Onko oppitunti ”MemoryLayout ja kohdistus” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Swift Academy-oppimispolun 3 oppituntia, myös oppitunnin “MemoryLayout ja kohdistus”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Swift Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”MemoryLayout ja kohdistus”?
Tutki tyyppien koon, stride-arvon ja kohdistuksen. Harjoittelet Swift Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Swift Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Swift Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.
Kuinka kauan ”MemoryLayout ja kohdistus”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Swift Academy-oppitunnilla?
Kyllä. Jokainen Swift Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- MemoryLayout ja kohdistus
- UnsafePointer ja UnsafeMutablePointer
- Unsafe-puskuriosoittimet
- withUnsafeBytes ja C-yhteentoimivuus