Swift Silpnas Nuorodos

Išversta iš anglų kalbos https://www.mikeash.com/pyblog/friday-qa-2015-12-11-swift-weak-references.html

Tuo atveju, jei jums buvo Marse, urvas, su savo akimis uždarytas ir pirštais ausis, Swift buvo atviras rangovų. Tai labai patogu naršyti vienas iš įdomesnių funkcijų, Swift įgyvendinimas: kaip silpnas nuorodos darbą.

Silpnas Nuorodos
Į šiukšlių surinkta, ar nuoroda, skaičiuojami kalba, stiprus nuorodos yra vienas, kuris saugo tikslinę objekto gyvas. Silpnas nuorodos yra vienas, kuris nėra. Daiktas negali būti sunaikinti, o yra daug nuorodų į jį, tačiau ji gali būti sunaikinta, nors yra silpnas nuorodų į jį.

Kai mes sakome “silpna nuoroda” mes paprastai tai naujo silpnas nuoroda. Tai yra, kai tikslinė silpnas nuoroda yra sunaikinta, silpnas nuoroda tampa lygus nuliui. Tai taip pat įmanoma, kad ne naujo silpnas nuorodos, kurios gaudyklės, avarijos, arba remtis nosies demonai. Tai, ką jūs gaunate, kai jūs naudojate unsafe_unretained Objective-C, arba unowned, Swift. (Atminkite, kad Objective-C suteikia mums nosies-demonų versija, o Swift rūpinasi, kad avarijos patikimai.)

Naujo silpnas nuorodos yra patogu, kad aplink, ir jie yra labai naudinga nuoroda, skaičiuojami kalbomis. Jie leidžia apskrito nuorodos į egzistuoti be kuriant išlaikyti ciklų, ir nereikia rankiniu būdu pertraukos atgal nuorodos. Jie tokie naudingi, kad aš sukūriau savo versiją silpnas nuorodos atgal prieš Apple pristatė ARC ir padaryta kalbos lygio silpnas nuorodos prieinama ne šiukšlių surinkti kodą.

Kaip Tai Veikia?
Tipiškas įgyvendinimo naujo silpnas nuorodos yra išlaikyti visas sąrašas silpnas nuorodomis į kiekvieną objektą. Kai silpnas nuoroda yra sukurtas daiktas, kad nuoroda būtų įtraukta į sąrašą. Kai kurios nuorodos yra paskiriamas arba eina paieska, jis bus pašalintas iš sąrašo. Kai objektas sunaikintas visas nuorodas sąraše yra nulinė. Į wielowątkowego aplinkos (t. y. visi jie šių dienų), įgyvendinimas turi sinchronizuoti gauti silpnas nuoroda ir sunaikinti objektą, siekiant išvengti lenktynių sąlygomis, kai viena gija spaudai paskutinis stiprus nuoroda į objektą tuo pačiu metu kitoje temoje bando įkelti silpnas nuoroda į jį.

Mano įgyvendinimą, kiekviena silpna nuoroda yra pilnavertis daiktas. Sąrašą silpnas nuorodos yra tik silpni nuoroda objektus. Tai prideda neefektyvumo, nes papildomų indirection ir atminties naudojimą, bet tai patogu turėti nuorodas būti visiškai objektus.

Apple a Objective-C įgyvendinimą, kiekviena silpna nuoroda yra paprastas žymiklį į tikslą, objektą. O ne skaityti ir rašyti nurodymus, tiesiogiai, kompiliatorius naudoja padėjėjo funkcijas. Jei ketinate silpnos rodykle, saugojimo funkcija registrų žymiklį vietą kaip silpnas nuoroda į tikslą. Skaitant iš silpna rodykle, skaityti funkcija sujungia su nuoroda skaičiavimo sistemą, siekiant užtikrinti, kad ji niekada grąžina žymiklį į objektą, kuris yra deallocated.

Naujo Veiksmo
Tegul kurti tiek kodų, todėl mes galime žiūrėti šių dalykų atsitikti.

Mes norime, kad būtų galima išmesti turinio objektą atmintyje. Ši funkcija mano regionas atminties, pertraukos ji į žymiklį dydžio gabaliukus, ir pasirodo visa tai į patogų hex eilutė:

 func contents(ptr: UnsafePointer<Void>, _ length: Int) -> String {
        let wordPtr = UnsafePointer<UInt>(ptr)
        let words = length / sizeof(UInt.self)
        let wordChars = sizeof(UInt.self) * 2

        let buffer = UnsafeBufferPointer<UInt>(start: wordPtr, count: words)
        let wordStrings = buffer.map({ word -> String in
            var wordString = String(word, radix: 16)
            while wordString.characters.count < wordChars {
                wordString = "0" + wordString
            }
            return wordString
        })
        return wordStrings.joinWithSeparator(" ")
    }

Kitą funkciją, sukuria savivartis funkciją objektą. Vadinu tai, kai su objektu, ir jis grąžina funkcija, kad bus sąvartynas turinio šį objektą. Šalies viduje, ji išsaugo yra UnsafePointer objektą greičiau nei naudojant įprastą nuorodą. Tai užtikrina, kad jis neturi bendrauti su kalba tai nuoroda skaičiavimo sistemą. Jis taip pat leidžia mums, kad sąvartynas atminties objektą po to, kai jis buvo sunaikinta, kuri bus naudinga vėliau.

    func dumperFunc(obj: AnyObject) -> (Void -> String) {
        let objString = String(obj)
        let ptr = unsafeBitCast(obj, UnsafePointer<Void>.self)
        let length = class_getInstanceSize(obj.dynamicType)
        return {
            let bytes = contents(ptr, length)
            return "\(objString) \(ptr): \(bytes)"
        }
    }

Čia tai klasė, kuri egzistuoja turėti silpnas nuorodą, kad galėtume patikrinti, ar ji. Aš pridėjo fiktyvių kintamųjų abiejų pusių, kad būtų aišku, kur silpna nuoroda gyvena atminties kelties:

   class WeakReferer {
        var dummy1 = 0x1234321012343210
        weak var target: WeakTarget?
        var dummy2: UInt = 0xabcdefabcdefabcd
    }

Tegul suteikti jai pabandyti! Mes jums pradėti kurti persiuntėjo ir dempingo:

    let referer = WeakReferer()
    let refererDump = dumperFunc(referer)
    print(refererDump())

Spausdinama:

WeakReferer 0x00007f8a3861b920: 0000000107ab24a0 0000000200000004 1234321012343210 0000000000000000 abcdefabcdefabcd

Mes galime pamatyti isa pradžioje, po kurių kitų vidaus srityse. dummy1 užima 4-ąją riekė, ir dummy2 užima 6-ąją. Matome, kad silpnas nuoroda tarp jų yra nulis, kaip tikėtasi.

Tegul tašką, jis ne daiktas, dabar, ir pamatyti, kaip jis atrodo. Aš tai padaryti viduje ar blokuoti, kad mes galime kontroliuoti, kai tikslas eina paieska ir yra sunaikinamos:

    do {
        let target = NSObject()
        referer.target = target
        print(target)
        print(refererDump())
    }

Spausdinama:

<NSObject: 0x7fda6a21c6a0>
WeakReferer 0x00007fda6a000ad0: 00000001050a44a0 0000000200000004 1234321012343210 00007fda6a21c6a0 abcdefabcdefabcd

Kaip ir tikėtasi, rodyklė į tikslą yra saugomi tiesiogiai silpnas nuoroda. Tegul iškelties jį dar kartą po jos tikslas yra sunaikinti pabaigoje padaryti blokas:

   print(refererDump())
    WeakReferer 0x00007ffe32300060: 000000010cfb44a0 0000000200000004 1234321012343210 0000000000000000 abcdefabcdefabcd

Ji tampa nuliu. Puikiai!

Tiesiog dėl malonumo, leiskite pakartoti eksperimentą su gryno Swift objektas, kaip tikslą. Tai nėra malonu pareikšti Objective-C į nuotrauką, kai tai nėra būtina. Čia grynas, Swift tikslas:

   class WeakTarget {}

Pabandykime tai išsiaiškinti:

    let referer = WeakReferer()
    let refererDump = dumperFunc(referer)
    print(refererDump())
    do {
        class WeakTarget {}
        let target = WeakTarget()
        referer.target = target
        print(refererDump())
    }
    print(refererDump())

Tikslinės prasideda nuliu, kaip ir tikėtasi, tada bus priskirtos:

WeakReferer 0x00007fbe95000270: 00000001071d24a0 0000000200000004 1234321012343210 0000000000000000 abcdefabcdefabcd
WeakReferer 0x00007fbe95000270: 00000001071d24a0 0000000200000004 1234321012343210 00007fbe95121ce0 abcdefabcdefabcd

Tada, kai tikslas nueina, nuoroda turėtų būti nustatytas nulis:

WeakReferer 0x00007fbe95000270: 00000001071d24a0 0000000200000004 1234321012343210 00007fbe95121ce0 abcdefabcdefabcd

O dieve. Ji nebuvo gauti nuliu. Gal tikslinės negavau sunaikinta. Kažkas turi būti išlaikyti jį gyvą! Leiskite dar kartą patikrinkite:

    class WeakTarget {
        deinit { print("WeakTarget deinit") }
    }

Veikia kodą dar kartą, mes gauname:

WeakReferer 0x00007fd29a61fa10: 0000000107ae44a0 0000000200000004 1234321012343210 0000000000000000 abcdefabcdefabcd
WeakReferer 0x00007fd29a61fa10: 0000000107ae44a0 0000000200000004 1234321012343210 00007fd29a42a920 abcdefabcdefabcd
WeakTarget deinit
WeakReferer 0x00007fd29a61fa10: 0000000107ae44a0 0000000200000004 1234321012343210 00007fd29a42a920 abcdefabcdefabcd

Taip, tai vyksta toli, bet silpnas nuoroda neveikia, yra nulinė. Kaip apie tai, mes nustatėme, kad klaida Swift! Tai nuostabu, kad jis nebuvo fiksuotas, po visą šį laiką. Jūs manote, kad kas nors būtų pastebėjau, iki dabar. Eikime į priekį ir kurti gražus avarijos pasiekti nuoroda, tada mes galime failą klaidą Swift projektas:

    let referer = WeakReferer()
    let refererDump = dumperFunc(referer)
    print(refererDump())
    do {
        class WeakTarget {
            deinit { print("WeakTarget deinit") }
        }
        let target = WeakTarget()
        referer.target = target
        print(refererDump())
    }
    print(refererDump())
    print(referer.target)

Čia ateina avarijos:

WeakReferer 0x00007ff7aa20d060: 00000001047a04a0 0000000200000004 1234321012343210 0000000000000000 abcdefabcdefabcd
WeakReferer 0x00007ff7aa20d060: 00000001047a04a0 0000000200000004 1234321012343210 00007ff7aa2157f0 abcdefabcdefabcd
WeakTarget deinit
WeakReferer 0x00007ff7aa20d060: 00000001047a04a0 0000000200000004 1234321012343210 00007ff7aa2157f0 abcdefabcdefabcd
nil

O dieve kvadratu! Kur kaboom? Ten turėjo būti pribloškiantis kaboom! Išvesties sako, kad viskas veikia po visų, bet mes galime aiškiai pamatyti iš iškelties, kad jis neveikia ne visiems.

Leiskite apžiūrėti viską labai atidžiai. Štai pataisytas WeakTarget su fiktyvus kintamasis, kad ji gražiau sąvartyną, jos turinys, taip pat:

    class WeakTarget {
        var dummy = 0x0123456789abcdef

        deinit {
            print("Weak target deinit")
        }
    }

Štai keletas naujų kodą, kuris eina per pačią procedūrą ir išverčia abu objektai kiekviename žingsnyje:

    let referer = WeakReferer()
    let refererDump = dumperFunc(referer)
    print(refererDump())
    let targetDump: Void -> String
    do {
        let target = WeakTarget()
        targetDump = dumperFunc(target)
        print(targetDump())

        referer.target = target

        print(refererDump())
        print(targetDump())
    }
    print(refererDump())
    print(targetDump())
    print(referer.target)
    print(refererDump())
    print(targetDump())

Peržiūrėkime produkcijos. Į persiuntėjo pradeda gyvenimą kaip ir anksčiau, su nuliu-iš tikslinė sritis:

WeakReferer 0x00007fe174802520: 000000010faa64a0 0000000200000004 1234321012343210 0000000000000000 abcdefabcdefabcd

Tikslinės pradeda gyvenimą kaip normali objektas, įvairių antraščių laukai po mūsų manekeno srityje:

WeakTarget 0x00007fe17341d270: 000000010faa63e0 0000000200000004 0123456789abcdef

Nuo priskirti tikslinei srityje, mes galime pamatyti žymiklį vertę, gauti užpildyti:

WeakReferer 0x00007fe174802520: 000000010faa64a0 0000000200000004 1234321012343210 00007fe17341d270 abcdefabcdefabcd

Tikslinės yra daug, kaip ir anksčiau, bet vienas iš antraštės laukeliai, padidėjo 2:

WeakTarget 0x00007fe17341d270: 000000010faa63e0 0000000400000004 0123456789abcdef

Tikslinės bus sunaikinti, kaip tikėtasi:

Weak target deinit

Mes matome persiuntėjo objektas vis dar yra rodyklė į tikslą:

WeakReferer 0x00007fe174802520: 000000010faa64a0 0000000200000004 1234321012343210 00007fe17341d270 abcdefabcdefabcd

Ir tikslinės pati vis dar atrodo labai gyvas, nors skirtingos antraštės laukas sumažėjo 2, palyginti su paskutinį kartą mes matėme tai:

WeakTarget 0x00007fe17341d270: 000000010faa63e0 0000000200000002 0123456789abcdef

Pasiekti target srityje, gamina nulis nors jis nebuvo nuliu:

    nil

Dempingo persiuntėjo dar kartą rodo, kad vien tik aktas pasiekti tikslą srityje buvo pakeisti. Dabar ji yra nulinė:

WeakReferer 0x00007fe174802520: 000000010faa64a0 0000000200000004 1234321012343210 0000000000000000 abcdefabcdefabcd

Objektas yra dabar visiškai sunaikinimo:

WeakTarget 0x00007fe17341d270: 200007fe17342a04 300007fe17342811 ffffffffffff0002

Daugiau ir įdomiau. Mes matėme antraštės laukeliai didinimo ir decremeting truputį, leiskite pamatyti, jei mes galime padaryti, kad įvyktų daugiau:

    let target = WeakTarget()
    let targetDump = dumperFunc(target)
    do {
        print(targetDump())
        weak var a = target
        print(targetDump())
        weak var b = target
        print(targetDump())
        weak var c = target
        print(targetDump())
        weak var d = target
        print(targetDump())
        weak var e = target
        print(targetDump())

        var f = target
        print(targetDump())
        var g = target
        print(targetDump())
        var h = target
        print(targetDump())
        var i = target
        print(targetDump())
        var j = target
        print(targetDump())
        var k = target
        print(targetDump())
    }
    print(targetDump())

Spausdinama:

 

Matome, kad pirmuoju numeriu šiame antraštės laukas eina iki 2 su kiekviena nauja silpnas nuoroda. Antrasis skaičius išauga iki 4 su kiekviena nauja stiprus nuoroda.

Apibendrinti, štai, ką mes matėme iki šiol:

  • Silpnas patarimų, atrodo kaip įprasti patarimų atmintinė.
  • Kai silpnas taikinio deinit veikia, tikslas yra ne deallocated, ir silpna žymiklį yra ne nulinė.
  • Kai silpnas žymiklį yra prieinama po taikinio deinit veikia, jis yra nuliu dėl prieigos ir silpna tikslas yra deallocated.
  • Silpnas tikslo yra nuoroda skaičius silpnas nuorodos, atskiri skaičius stiprus nuorodos.

Swift Kodas
Dabar, Swift atidaryta šaltinio,, mes iš tikrųjų galite eiti susieti tai pastebėti elgesio kodo.

Swift standartinė biblioteka yra objektų, skirtų stos su HeapObject tipas įsikūręs stdlib/public/SwiftShims/HeapObject.h. Jis atrodo:

    struct HeapObject {
    /// This is always a valid pointer to a metadata object.
    struct HeapMetadata const *metadata;

    SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
    // FIXME: allocate two words of metadata on 32-bit platforms

    #ifdef __cplusplus
    HeapObject() = default;

    // Initialize a HeapObject header as appropriate for a newly-allocated object.
    constexpr HeapObject(HeapMetadata const *newMetadata) 
        : metadata(newMetadata)
        , refCount(StrongRefCount::Initialized)
        , weakRefCount(WeakRefCount::Initialized)
    { }
    #endif
    };

Lauko metadata Swift ekvivalentas isa srityje Objective-C, ir iš tikrųjų ji yra suderinama. Tada yra šie NON_OBJC_MEMBERS apibrėžta makro:

    #define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
      StrongRefCount refCount;                      \
      WeakRefCount weakRefCount

Na, atrodo, kad! Ten yra mūsų dviejų nuoroda skaičiuoja.

(Bonus klausimas: kodėl yra stiprus skaičius pirma čia, o nuotaikos virš silpnas skaičius buvo pirmas?)

Nuoroda skaičiuoja valdo krūva funkcijų įsikūręs stdlib/public/runtime/HeapObject.cpp. Pavyzdžiui, štai swift_retain:

    void swift::swift_retain(HeapObject *object) {
    SWIFT_RETAIN();
        _swift_retain(object);
    }
    static void _swift_retain_(HeapObject *object) {
        _swift_retain_inlined(object);
    }
    auto swift::_swift_retain = _swift_retain_;

Yra daugybė indirection, bet galiausiai jis ragina per šį inline funkcijos antraštė:

    static inline void _swift_retain_inlined(HeapObject *object) {
      if (object) {
        object->refCount.increment();
      }
    }

Kaip jūs tikitės, ji padidina nuoroda skaičius. Štai įgyvendinimo increment:

    void increment() {
      __atomic_fetch_add(&refCount, RC_ONE, __ATOMIC_RELAXED);
    }

RC_ONE ateina iš enum:

    enum : uint32_t {
      RC_PINNED_FLAG = 0x1,
      RC_DEALLOCATING_FLAG = 0x2,

      RC_FLAGS_COUNT = 2,
      RC_FLAGS_MASK = 3,
      RC_COUNT_MASK = ~RC_FLAGS_MASK,

      RC_ONE = RC_FLAGS_MASK + 1
    };

Mes galime pamatyti, kodėl tas skaičius padidėjo 4 su kiekviena nauja stiprus nuoroda. Pirmieji du bitai srityje naudojamos vėliavėlės. Žvelgiant atgal į sąvartynus, mes galime pamatyti tų vėliavėlių veiksmų. Štai silpnas tikslą prieš ir po paskutinio stipraus nuoroda nuėjo:

    WeakTarget 0x00007fe17341d270: 000000010faa63e0 0000000400000004 0123456789abcdef
    Weak target deinit
    WeakTarget 0x00007fe17341d270: 000000010faa63e0 0000000200000002 0123456789abcdef

Į lauką išėjo iš 4, reiškiantis nuoroda skaičius 1 ir nr. vėliavas, 2, reiškiantis nuoroda skaičius lygus nuliui, o RC_DEALLOCATING_FLAG nustatyti. Šis pranešimas-deinit objektas yra dedamas į kažkokią DEALLOCATING nežinioje.

(Beje, kas yra RC_PINNED_FLAG? Aš baksnodavo per kodu ir negalėjo suprasti, nieko už tai, kad jį,, rodo “prisegta objektas”, kuris yra jau gana akivaizdu iš pavadinimo. Jei jūs figure it out ar turi informuoti atspėti, prašome rašyti komentarą.)

Tegul patikrinti silpnas nuoroda grafo įgyvendinimas, o mes čia. Tai yra tos pačios rūšies enum:

    enum : uint32_t {
      // There isn't really a flag here.
      // Making weak RC_ONE == strong RC_ONE saves an
      // instruction in allocation on arm64.
      RC_UNUSED_FLAG = 1,

      RC_FLAGS_COUNT = 1,
      RC_FLAGS_MASK = 1,
      RC_COUNT_MASK = ~RC_FLAGS_MASK,

      RC_ONE = RC_FLAGS_MASK + 1
    };

Štai kur 2 kilęs iš: yra paliekama vietos viena vėliava, kuri šiuo metu yra nenaudojamas. Keista, komentaras šis kodas atrodo, kad neteisingas, nes RC_ONE čia yra lygi 2, o stiprus RC_ONE yra lygus 4. Aš manau, kad jie vieną kartą buvo lygus, ir tada jis buvo pakeistas ir komentaras, nebuvo atnaujinta. Tiesiog eina į rodo, kad komentarai yra nenaudingas, ir jūs neturėtumėte kada nors rašyti.

Kaip visa tai susieti su pakrovimo silpnas nuorodos? Tai būtų tvarkomi funkcija vadinama 

swift_weakLoadStrong:

    HeapObject *swift::swift_weakLoadStrong(WeakReference *ref) {
      auto object = ref->Value;
      if (object == nullptr) return nullptr;
      if (object->refCount.isDeallocating()) {
        swift_weakRelease(object);
        ref->Value = nullptr;
        return nullptr;
      }
      return swift_tryRetain(object);
    }

Iš to, aišku, kaip tingus naujo darbų. Kai pakrovimo silpnas nuorodą, jei objektas yra deallocating, zero out nuoroda. Priešingu atveju, stenkitės išlaikyti užsibrėžtą tikslą, ir jį grąžinti. Kasti šiek tiek toliau, mes galime pamatyti, kaip swift_weakRelease deallocates objektą atmintyje, jei tai paskutinė nuoroda:

    void swift::swift_weakRelease(HeapObject *object) {
      if (!object) return;

      if (object->weakRefCount.decrementShouldDeallocate()) {
        // Only class objects can be weak-retained and weak-released.
        auto metadata = object->metadata;
        assert(metadata->isClassObject());
        auto classMetadata = static_cast<const ClassMetadata*>(metadata);
        assert(classMetadata->isTypeMetadata());
        swift_slowDealloc(object, classMetadata->getInstanceSize(),
                          classMetadata->getInstanceAlignMask());
      }
    }

(Pastaba: jei jūs ieškote kodo saugykla, pavadinimų pasikeitė naudoti “unowned” vietoj to “silpna” daugeliu atvejų. Įvardijimo aukščiau yra srove naujausias fotografiją kaip laiko apie tai rašyti, tačiau plėtra juda. Jūs galite peržiūrėti saugykla, 2.2 fotografiją matyti, kaip aš jį čia, arba patraukti naujausius tačiau reikia žinoti pavadinimų pakeitimus, ir, galbūt, įgyvendinti pokyčius.)

Išleidimą tai Visi Kartu
Mes matėme, jis visus iš viršaus į apačią dabar. Kas yra aukšto lygio nuomonę apie tai, kaip Swift silpnas nuorodos iš tikrųjų dirba?

  1. Silpnas nuorodos yra tik nuorodos į tikslą, objektą.
  2. Silpnas nuorodos nėra individualiai sekama taip, kaip jos Objective-C.
  3. Vietoj to, kiekvienas Swift objektas yra silpna, nuoroda skaičių prie savo tvirtą nuoroda skaičius.
  4. Swift decouples objektas deinitialization nuo objekto deallocation. Daiktas gali būti deinitialized, išlaisvinti savo išorės išteklių, be deallocating atminties užima objekto pats.
  5. Kai Swift objekto stiprus nuoroda skaičius pasiekia nulį, o silpna, skaičius yra dar didesnis nei nulis, objektas yra deinitialized, bet ne deallocated.
  6. Tai reiškia, kad silpnas patarimų, į deallocated objektas vis dar galioja, patarimų ir gali būti dereferenced be kritimo arba krovinio šiukšlių duomenis. Jie tik rodo, kad objektas, į zombie narė.
  7. Kai silpnas nuoroda yra pakrautas, runtime patikrinimus tikslinės valstybės. Jeigu tikslas yra zombie, tada jis zeroes silpnas nuoroda, sumažina charytatywny silpnas nuoroda skaičius, ir grįžta nil.
  8. Kai visi silpnas nuorodos į zombie objektas yra nulinė, zombie yra deallocated.

Šis dizainas turi kai kurių įdomių pasekmių, palyginti su Objective-C:

  • Sąrašo nėra silpna nuorodos išlaikyti bet kur. Tai supaprastina kodas ir pagerina efektyvumą.
  • Nėra konkuravimo sąlygos tarp naujo silpnas nuorodą viena gija, ir pakrovimo, kad silpnas nuoroda kitoje temoje. Tai reiškia, kad krovimo silpnas nuoroda ir sunaikinti silpnai nuoroda objektas gali būti padaryta neturėdami spynos. Tai pagerina efektyvumą.
  • Silpnas nuorodos į daiktas bus sukelti, kad objektas atmintyje išliks skiriama net po to, nėra stiprus nuorodų į jį, kol visi silpnas nuorodos yra arba pakrauti arba atmetami. Tai laikinai padidina atminties naudojimas. Atkreipkite dėmesį, kad poveikis yra nedidelis, nes, o tikslinį objektą atmintyje, tebegalioja, tai tik atminties instancijos pati. Visų išorinių išteklių (įskaitant sandėliavimą, Masyvas ar Žodynas savybės) yra išgrynintas, kai paskutinis stiprus nuoroda nueina. Silpnas nuoroda gali sukelti vieną egzempliorių pasilikti paskirstyti, tačiau ne visai medžio objektus.
  • Papildoma atmintis privalo saugoti silpnas nuoroda skaičiuoti kiekvieno objekto. Atrodo, kad tai yra nelogiškas ant 64-bit. Antraštės laukų norite užima visą skaičius žymiklį dydžio gabaliukus, ir stiprus, ir silpnas nuoroda skaičiuoja dalintis viena. Jei silpnas nuoroda skaičius ten nebuvo, stiprus nuoroda tikėtis būtų tiesiog užima 64 bitų pati. Tai įmanoma, kad stiprus nuoroda priešingu atveju gali būti perkeltas į isa naudojant ne-rodyklė isa, bet aš nesu įsitikinęs, kaip svarbu, kad yra, arba, kaip tai vyksta purtyti iš ilguoju laikotarpiu. 32-bit, atrodo, kad silpna skaičius didėja objektas dydžių iki keturių baitų. Svarba 32-bitų mažėja kiekvieną dieną, tačiau.
  • Nes gauti silpnas žymiklį yra taip pigiai, tas pats mechanizmas gali būti naudojamas siekiant įgyvendinti patikimą semantika už unowned. Po gaubtu, unowned veikia lygiai taip weak, kaip silpni, išskyrus tai, kad nepavyksta garsiai, jei objektas nuėjo, o ne grįžta nėra. Objective-C, __unsafe_unretained yra įgyvendinama kaip žalio rodyklė su neapibrėžta elgesį, jei jį pasiekti vėlai, nes jis turėjo būti greitas, ir pakrovimo silpnas žymiklį yra šiek tiek lėtai.

Išvada
Swift silpnas patarimų naudoti įdomus požiūris, kuris suteikia tikslumą, greitį ir atminties virš galvos. Stebėjimo silpnas nuoroda skaičiuoti kiekvieno objekto ir atribojimo objektas deinitialization iš objct deallocation, silpnas nuorodos gali būti sprendžiamos tiek, saugiai ir greitai. Prieinamumas kodo standartas biblioteka leidžia tiksliai matyti tai, kas vyksta šaltinio lygio, o ne groveling per disassemblies ir atminties sąvartynų, kaip mes dažnai darome. Žinoma, kaip matote aukščiau, tai sunku nutraukti, kad įprotis visiškai.

 

Grįžti į pagrindinį

Leave a Reply

Your email address will not be published. Required fields are marked *