Kebocoran apa yang tidak dihitung atau dihitung oleh penghitungan referensi otomatis di Objective-C?

235

Pada platform Mac dan iOS, kebocoran memori sering disebabkan oleh pointer yang belum dirilis. Secara tradisional, itu selalu sangat penting untuk memeriksa semua dokumen Anda, salinan dan mempertahankan untuk memastikan masing-masing memiliki pesan rilis yang sesuai.

Toolchain yang dilengkapi dengan Xcode 4.2 memperkenalkan penghitungan referensi otomatis (ARC) dengan versi terbaru dari kompiler LLVM , yang benar-benar menghilangkan masalah ini dengan membuat kompiler mengelola memori barang-barang Anda untuk Anda. Itu cukup keren, dan itu memotong banyak waktu yang tidak perlu, waktu pengembangan duniawi dan mencegah banyak kebocoran memori ceroboh yang mudah diperbaiki dengan mempertahankan / melepaskan keseimbangan yang tepat. Bahkan kumpulan autorelease perlu dikelola secara berbeda ketika Anda mengaktifkan ARC untuk aplikasi Mac dan iOS Anda (karena Anda tidak seharusnya mengalokasikan sendiri milik Anda NSAutoreleasePoollagi).

Tapi apa yang lainnya memori kebocoran apakah itu tidak mencegah itu saya masih harus diwaspadai?

Sebagai bonus, apa perbedaan antara ARC di Mac OS X dan iOS, dan pengumpulan sampah di Mac OS X?

BoltClock
sumber

Jawaban:

262

Masalah terkait memori utama yang masih harus Anda perhatikan adalah mempertahankan siklus. Ini terjadi ketika satu objek memiliki pointer kuat ke yang lain, tetapi objek target memiliki pointer kuat kembali ke aslinya. Bahkan ketika semua referensi lain untuk objek-objek ini dihapus, mereka masih akan saling berpegangan dan tidak akan dirilis. Ini juga dapat terjadi secara tidak langsung, dengan rantai objek yang mungkin memiliki yang terakhir dalam rantai merujuk kembali ke objek sebelumnya.

Karena alasan inilah maka kualifikasi __unsafe_unretaineddan __weakkepemilikan ada. Yang pertama tidak akan mempertahankan objek yang ditunjuknya, tetapi membuka kemungkinan objek itu akan pergi dan menunjuk ke memori yang buruk, sedangkan yang terakhir tidak mempertahankan objek dan secara otomatis mengatur sendiri sampai nol ketika targetnya dialokasikan. Dari keduanya, __weakumumnya lebih disukai pada platform yang mendukungnya.

Anda akan menggunakan kualifikasi ini untuk hal-hal seperti delegasi, di mana Anda tidak ingin objek mempertahankan delegasinya dan berpotensi menyebabkan siklus.

Beberapa masalah terkait memori yang signifikan adalah penanganan benda-benda Yayasan Core dan memori yang dialokasikan menggunakan malloc()untuk jenis seperti char*. ARC tidak mengelola tipe-tipe ini, hanya objek Objective-C, jadi Anda masih harus menghadapinya sendiri. Jenis Core Foundation bisa sangat rumit, karena kadang-kadang mereka perlu dijembatani untuk mencocokkan objek Objective-C, dan sebaliknya. Ini berarti bahwa kontrol perlu ditransfer bolak-balik dari ARC ketika menjembatani antara tipe CF dan Objective-C. Beberapa kata kunci yang terkait dengan bridging ini telah ditambahkan, dan Mike Ash memiliki deskripsi yang bagus tentang berbagai case bridging dalam penulisan ARC yang panjang .

Selain itu, ada beberapa kasus lain yang lebih jarang, tetapi masih berpotensi bermasalah, yang spesifikasi terperincinya dipublikasikan secara terperinci.

Sebagian besar perilaku baru, berdasarkan pada menjaga benda-benda di sekitar selama ada pointer yang kuat untuk mereka, sangat mirip dengan pengumpulan sampah di Mac. Namun, dasar-dasar teknis sangat berbeda. Daripada memiliki proses pengumpul sampah yang berjalan secara berkala untuk membersihkan objek yang tidak lagi diarahkan, gaya manajemen memori ini bergantung pada aturan mempertahankan / melepaskan yang kaku yang kita semua harus patuhi dalam Objective-C.

ARC hanya mengambil tugas manajemen memori berulang yang harus kami lakukan selama bertahun-tahun dan menurunkannya ke kompiler sehingga kami tidak perlu khawatir lagi. Dengan cara ini, Anda tidak memiliki masalah penghentian atau profil memori gigi gergaji berpengalaman pada platform pengumpulan sampah. Saya sudah mengalami kedua hal ini di sampah saya mengumpulkan aplikasi Mac, dan saya ingin melihat bagaimana mereka berperilaku di bawah ARC.

Untuk informasi lebih lanjut tentang pengumpulan sampah vs. ARC, lihat respons yang sangat menarik ini oleh Chris Lattner di milis Objective-C , di mana ia mendaftar banyak keuntungan ARC dibandingkan pengumpulan sampah Objective-C 2.0. Saya telah mengalami beberapa masalah GC yang dia jelaskan.

Brad Larson
sumber
2
Terima kasih atas jawaban detailnya. Saya memiliki masalah yang sama di mana saya mendefinisikan delegasi di bawah _unsafe_unretained dan membuat aplikasi saya crash, kemudian memperbaikinya dengan mengubahnya menjadi kuat tetapi sekarang memiliki kebocoran memori. Jadi, saya mengubahnya menjadi lemah dan bekerja seperti pesona.
chathuram
@ichathura Wow! Anda menyelamatkan saya dari lumpur ARC. Saya mengalami crash yang sama ketika menggunakan CMPopTipView.
Nianliang
@BradLarson: "Anda tidak memiliki masalah penghentian atau profil memori gigi gergaji berpengalaman pada platform pengumpulan sampah". Saya berharap lebih buruk menghentikan dan profil memori gigi gergaji dari reklamasi berbasis lingkup dan kinerja yang jauh lebih buruk dari penghitungan referensi jadi saya ingin melihat perbandingan nyata.
Jon Harrop
Brad, tautan dari Chris Lattner sudah mati . Saya tidak 100% tetapi saya menemukan tautan lain ini. Yang saya pikir adalah apa yang ingin Anda tautkan ke: lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160208/…
Honey
1
@ Madu - Terima kasih telah menunjukkan itu. Yang Anda tautkan sedikit berbeda, tetapi saya mengganti tautan yang mati dengan versi yang diarsipkan dari pesan aslinya. Ada di arsip milis, yang seharusnya tersedia di suatu tempat, tetapi saya akan mencari tahu apakah saya dapat menemukan lokasi baru mereka.
Brad Larson
14

ARC tidak akan membantu Anda dengan memori non-ObjC, misalnya jika Anda melakukan malloc()sesuatu, Anda masih membutuhkannya free().

ARC dapat dibodohi oleh performSelector:jika kompiler tidak dapat mengetahui apa pemilih itu (kompiler akan menghasilkan peringatan tentang itu).

ARC juga akan menghasilkan kode mengikuti konvensi penamaan ObjC, jadi jika Anda mencampur ARC dan kode MRC Anda bisa mendapatkan hasil yang mengejutkan jika kode MRC tidak melakukan apa yang menurut kompiler menjanjikan nama-nama itu.

Garis-garis
sumber
7

Saya mengalami kebocoran memori dalam aplikasi saya karena 4 masalah berikut:

  1. Tidak membatalkan NSTimers ketika mengabaikan pengontrol tampilan
  2. Lupa menghapus pengamat apa pun ke NSNotificationCenter saat menolak pengontrol tampilan.
  3. Menyimpan referensi yang kuat untuk diri sendiri di blok.
  4. Menggunakan referensi kuat untuk delegasi dalam tampilan controller properti

Untungnya saya menemukan posting blog berikut dan dapat memperbaikinya: http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four- maybe-culprits/

Ed-E G
sumber
0

ARC juga tidak akan mengelola jenis CoreFoundation. Anda dapat 'menjembatani' mereka (Menggunakan CFBridgingRelease()) tetapi hanya jika Anda akan menggunakannya sebagai objek Objective-C / Cocoa. Perhatikan bahwa CFBridgingRelease hanya mengurangi CoreFoundation dengan jumlah 1 dan memindahkannya ke ARC Objective-C.

MaddTheSane
sumber
0

Xcode 9 menyediakan alat yang hebat untuk menemukan masalah semacam itu. Ini disebut: " Grafik Memori Debug ". Dengan menggunakannya Anda dapat menemukan objek yang bocor menurut jenis kelas dan Anda dapat melihat dengan jelas siapa yang memiliki referensi kuat untuk itu, dengan melepaskannya dari sana menyelesaikan masalah Anda. Itu juga mendeteksi siklus memori.

Lihat info lebih lanjut tentang cara menggunakannya

AKAN K.
sumber