Swift Academy · Oppitunti

MemoryLayout ja kohdistus

Tutki tyyppien koon, stride-arvon ja kohdistuksen.

Oppitunti 1/413 vaihetta

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)    // 8

size — 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 // 160

alignment — 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)  // 8

size- 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) // 16

Kenttien 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) // 8

Uudelleenjä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 reference

Optionalit 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 byte

of:-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)) // 8

Varaaminen 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.

Aloita maksutta

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

  1. MemoryLayout ja kohdistus
  2. UnsafePointer ja UnsafeMutablePointer
  3. Unsafe-puskuriosoittimet
  4. withUnsafeBytes ja C-yhteentoimivuus
← Takaisin: Swift Academy