Objective-C'deki otomatik referans sayımı ne tür sızıntıları önlemez veya en aza indirmez?


235

Mac ve iOS platformlarında, bellek sızıntılarına genellikle yayınlanmamış işaretçiler neden olur. Geleneksel olarak, her birinin ilgili bir yayın mesajına sahip olduğundan emin olmak için alaşımlarınızı, kopyalarınızı ve sakladığınızı kontrol etmek her zaman büyük önem taşımaktadır.

Xcode 4.2 ile gelen araç zinciri, LLVM derleyicisinin en son sürümü ile otomatik referans sayımı (ARC) sunar , derleyiciyi sizin için malzemelerinizi bellekle yönetmesini sağlayarak bu sorunu tamamen ortadan kaldırır . Bu oldukça havalı ve gereksiz, sıradan geliştirme süresini çok azaltıyor ve uygun tutma / bırakma dengesiyle düzeltilmesi kolay olan dikkatsiz bellek sızıntılarını önlüyor. Mac ve iOS uygulamalarınız için ARC'yi etkinleştirdiğinizde otomatik kiralama havuzlarının bile farklı şekilde yönetilmesi gerekir ( NSAutoreleasePoolartık kendi havuzlarınızı ayırmamanız gerekir ).

Ama başka hangi bellek sızıntıları hala dikkat etmem gerektiğini engellemiyor?

Bonus olarak, Mac OS X ve iOS'ta ARC ile Mac OS X'te çöp toplama arasındaki farklar nelerdir?

Yanıtlar:


262

Hala bilmeniz gereken birincil bellekle ilgili sorun, döngüleri korumaktır. Bu, bir nesnenin diğerine güçlü bir işaretçisi olduğunda, ancak hedef nesnenin orijinaline güçlü bir işaretçisi olduğunda oluşur. Bu nesnelere yapılan tüm diğer referanslar kaldırılsa bile, birbirlerine tutunacak ve serbest bırakılmayacaklardır. Bu, dolaylı olarak, zincirde sonuncusu daha önceki bir nesneye atıfta bulunabilecek bir nesne zinciri tarafından da olabilir.

Bu nedenle __unsafe_unretainedve __weaksahiplik niteleyicileri mevcuttur. Birincisi işaret ettiği herhangi bir nesneyi tutmayacak, ancak o nesnenin kaybolma ve kötü belleğe işaret etme olasılığını açık bırakırken, ikincisi nesneyi tutmuyor ve hedefi yeniden yerleştirildiğinde kendini otomatik olarak sıfır olarak ayarlıyor. Bu ikisinden __weakgenellikle onu destekleyen platformlarda tercih edilir.

Bu niteleyicileri, nesnenin temsilcisini korumasını ve potansiyel olarak bir döngüye yol açmasını istemediğiniz temsilciler gibi şeyler için kullanırsınız.

Belleğe ilişkin önemli bir başka endişe Core Foundation nesnelerinin işlenmesi ve malloc()benzeri tipler için ayrılan bellektir char*. ARC bu türleri yönetmez, sadece Objective-C nesnelerini yönetir, bu yüzden hala kendinizle başa çıkmanız gerekir. Çekirdek Temel türleri özellikle zor olabilir, çünkü bazen eşleşen Objective-C nesnelerine ve tam tersine köprülenmeleri gerekir. Bu, CF tipleri ile Objective-C arasında köprü oluştururken kontrolün ARC'den ileri geri aktarılması gerektiği anlamına gelir. Bu köprüleme ile ilgili bazı anahtar kelimeler eklendi ve Mike Ash, uzun ARC yazımında çeşitli köprüleme vakalarının harika bir açıklamasına sahip .

Buna ek olarak, yayınlanan spesifikasyonun ayrıntılı olarak ele alındığı daha az sıklıkta, ancak yine de potansiyel olarak problemli olan başka durumlar da vardır .

Nesneleri güçlü bir işaretçi olduğu sürece etrafta tutmaya dayanan yeni davranışların çoğu, Mac'teki çöp toplama işlemine çok benzer. Ancak, teknik temeller çok farklıdır. Artık işaretlenmeyen nesneleri temizlemek için düzenli aralıklarla çalışan bir çöp toplayıcı işlemine sahip olmak yerine, bu bellek yönetimi tarzı, Objective-C'de uymamız gereken katı tutma / bırakma kurallarına dayanır.

ARC, yıllarca yapmamız gereken tekrarlayan bellek yönetimi görevlerini alır ve derleyiciye boşaltır, böylece bir daha asla endişelenmemize gerek kalmaz. Bu şekilde, çöp toplanan platformlarda yaşanan durma problemleri veya testere dişi bellek profilleri olmaz. Bunların her ikisini de çöp toplama Mac uygulamalarında yaşadım ve ARC altında nasıl davrandıklarını görmek için sabırsızlanıyorum.

Çöp toplama ve ARC hakkında daha fazla bilgi için, Chris Lattner'ın Objective-C posta listesindeki birçok amacını listelediği Objective-C posta listesinde bu çok ilginç yanıta bakın . Açıkladığı birkaç GC sorunuyla karşılaştım.


2
Ayrıntılı cevap için teşekkürler. Ben _unsafe_unretained altında bir temsilci tanımladı ve benim uygulama çöktü var, daha sonra güçlü olarak değiştirerek düzeltildi aynı sorun vardı ama şimdi bir bellek sızıntısı var. Bu yüzden onu zayıf olarak değiştirdim ve bir cazibe gibi çalışıyor.
chathuram

@ichathura Vay canına! Beni ARC mire'den kurtardın. CMPopTipView kullanırken aynı çökme ile karşılaştım.
Nianliang

@BradLarson: "Çöp toplanan platformlarda yaşanan durma problemleriniz veya testere dişi bellek profilleriniz yok". Kapsam tabanlı ıslahtan daha kötü durma ve testere dişi bellek profilleri ve referans sayımından çok daha kötü performans bekliyorum, bu yüzden gerçek bir karşılaştırma görmek istiyorum.
Jon Harrop

Brad, Chris Lattner'ın bağlantısı öldü . % 100 değilim ama bu bağlantıyı buldum. Hangi bağlantı kurmak istediğinizi düşünüyorum: lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/…
Honey

1
@Honey - Bunu işaret ettiğiniz için teşekkürler. Bağladığınız kişi biraz farklı, ancak ölü bağlantıyı orijinal iletinin arşivlenmiş bir sürümüyle değiştirdim. Bir yerde mevcut olması gereken posta listesi arşivlerinde, ancak yeni konumlarını bulabileceğimi görmek için bakacağım.
Brad Larson

14

ARC, ObjC olmayan belleklerde size yardımcı olmaz, örneğin bir malloc()şey varsa , yine de buna ihtiyacınız vardır free().

performSelector:Derleyici, seçicinin ne olduğunu bulamazsa ARC sizi kandırabilir (derleyici bu konuda bir uyarı oluşturur).

ARC ayrıca ObjC adlandırma kurallarına göre kod üretecektir, bu nedenle ARC ve MRC kodunu karıştırırsanız, MRC kodu derleyicinin söz verdiği sözleri yapmazsa şaşırtıcı sonuçlar elde edebilirsiniz.


7

Aşağıdaki 4 sorun nedeniyle uygulamamda bellek sızıntıları yaşadım:

  1. Görünüm denetleyicilerini kapatırken NSTimerleri geçersiz kılmamak
  2. Görünüm denetleyicisini kapatırken NSNotificationCenter'daki tüm gözlemcileri kaldırmayı unutma.
  3. Kendine bloklar halinde güçlü referanslar tutmak.
  4. Görünüm denetleyicisi özelliklerindeki temsilcilere güçlü başvurular kullanma

Neyse ki aşağıdaki blog yayınına rastladım ve bunları düzelttim: http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-likely-culprits/


0

ARC ayrıca CoreFoundation tiplerini yönetmeyecektir. Sadece ' CFBridgingRelease()Objective-C / Cocoa nesnesi olarak kullanacaksanız ' köprüleyebilirsiniz '(Kullanarak ). CFBridgingRelease'in CoreFoundation tutma sayısını 1 azaltır ve Objective-C'nin ARC'sine taşır.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.