Bagaimana cara kerja mekanisme penghitungan referensi otomatis yang baru?


206

Adakah yang bisa menjelaskan secara singkat kepada saya bagaimana ARC bekerja? Saya tahu ini berbeda dari Pengumpulan Sampah, tetapi saya hanya bertanya-tanya bagaimana cara kerjanya.

Juga, jika ARC melakukan apa yang dilakukan GC tanpa menghalangi kinerja, lalu mengapa Java menggunakan GC? Mengapa tidak menggunakan ARC juga?


2
Ini akan memberi tahu Anda semua tentang hal itu: http://clang.llvm.org/docs/AutomaticReferenceCounting.html Bagaimana penerapannya di Xcode dan iOS 5 berada di bawah NDA.
Morten Fast

14
@mbehan Itu saran yang buruk. Saya tidak ingin masuk atau bahkan memiliki akun untuk pusat dev iOS, namun saya tertarik untuk mengetahui tentang ARC.
Andres F.

1
ARC tidak melakukan semua yang GC lakukan, itu mengharuskan Anda untuk bekerja dengan semantik referensi yang kuat dan lemah secara eksplisit, dan kebocoran memori jika Anda tidak mendapatkan yang benar. Dalam pengalaman saya, ini awalnya sulit ketika Anda menggunakan blok di Objective-C, dan bahkan setelah Anda mengetahui trik yang tersisa dengan beberapa kode boilerplate yang mengganggu (IMO) di sekitar banyak penggunaan blok. Lebih mudah untuk melupakan referensi kuat / lemah. Selain itu, GC dapat melakukan sedikit lebih baik daripada ARC wrt. CPU, tetapi membutuhkan lebih banyak memori. Ini bisa lebih cepat daripada manajemen memori eksplisit ketika Anda memiliki banyak memori.
TaylanUB

@AylanUB: "membutuhkan lebih banyak memori". Banyak orang mengatakan itu tetapi saya merasa sulit untuk percaya.
Jon Harrop

2
@ JonHarrop: Saat ini saya bahkan tidak ingat mengapa saya mengatakan itu, jujur ​​saja. :-) Sementara itu saya menyadari bahwa ada begitu banyak strategi GC yang berbeda sehingga pernyataan selimut semacam itu mungkin semuanya tidak berharga. Izinkan saya membaca Hans Boehm dari Mitos Alokasi Memori dan Setengah Kebenarannya : "Mengapa daerah ini sangat rentan terhadap kebijaksanaan rakyat yang meragukan?"
TaylanUB

Jawaban:


244

Setiap pengembang baru yang datang ke Objective-C harus mempelajari aturan kaku tentang kapan mempertahankan, melepaskan, dan objek autorelease. Aturan-aturan ini bahkan menentukan konvensi penamaan yang menyiratkan jumlah tetap objek yang dikembalikan dari metode. Manajemen memori di Objective-C menjadi kebiasaan kedua setelah Anda menerapkan aturan ini dengan hati-hati dan menerapkannya secara konsisten, tetapi bahkan pengembang Kakao yang paling berpengalaman pun akan tergelincir dari waktu ke waktu.

Dengan Clang Static Analyzer, para pengembang LLVM menyadari bahwa aturan-aturan ini cukup dapat diandalkan sehingga mereka dapat membangun alat untuk menunjukkan kebocoran memori dan overreleases dalam jalur yang diambil kode Anda.

Penghitungan referensi otomatis (ARC) adalah langkah logis berikutnya. Jika kompiler dapat mengenali di mana Anda harus menyimpan dan melepaskan objek, mengapa tidak memasukkannya untuk Anda? Tugas yang kaku dan berulang adalah apa yang dilakukan kompiler dan saudara-saudara mereka yang hebat. Manusia melupakan sesuatu dan membuat kesalahan, tetapi komputer jauh lebih konsisten.

Namun, ini tidak sepenuhnya membebaskan Anda dari kekhawatiran tentang manajemen memori pada platform ini. Saya menjelaskan masalah utama yang harus diperhatikan (mempertahankan siklus) dalam jawaban saya di sini , yang mungkin memerlukan sedikit pemikiran pada bagian Anda untuk menandai pointer lemah. Namun, itu kecil jika dibandingkan dengan apa yang Anda peroleh di ARC.

Bila dibandingkan dengan manajemen memori manual dan pengumpulan sampah, ARC memberi Anda yang terbaik dari kedua dunia dengan memotong kebutuhan untuk menulis kode penahan / pelepasan, namun tidak memiliki profil kehabisan memori dan gigi gergaji yang terlihat di lingkungan pengumpulan sampah. Tentang satu-satunya keuntungan pengumpulan sampah memiliki lebih dari ini adalah kemampuannya untuk berurusan dengan mempertahankan siklus dan fakta bahwa penugasan properti atom murah (seperti dibahas di sini ). Saya tahu saya mengganti semua kode Mac GC yang ada dengan implementasi ARC.

Seperti apakah ini dapat diperluas ke bahasa lain, tampaknya diarahkan pada sistem penghitungan referensi di Objective-C. Mungkin sulit untuk menerapkan ini pada Java atau bahasa lain, tapi saya tidak cukup tahu tentang detail kompiler tingkat rendah untuk membuat pernyataan definitif di sana. Mengingat bahwa Apple adalah pihak yang mendorong upaya ini dalam LLVM, Objective-C akan didahulukan kecuali pihak lain melakukan sumber daya signifikan mereka sendiri untuk ini.

Penyingkapan pengembang mengejutkan ini di WWDC, sehingga orang tidak menyadari bahwa hal seperti ini bisa dilakukan. Ini mungkin muncul di platform lain dari waktu ke waktu, tetapi untuk saat ini eksklusif untuk LLVM dan Objective-C.


56
penekanan saya: ini tidak sepenuhnya membebaskan Anda dari khawatir tentang manajemen memori
bshirley

6
Apakah ARC benar-benar sebuah inovasi? Dari jawaban Anda, saya menyimpulkan bahwa ARC adalah konsep baru, yang digunakan dalam Objective-C untuk pertama kalinya (koreksi saya jika saya salah). Sejujurnya, saya bukan pengembang Objective-C dan tidak tahu banyak tentang ARC, tetapi apakah Boost Shared Pointers (lihat boost.org) tidak persis sama? Dan jika tidak, apa bedanya?
theDmi

2
@DMM - Daripada mengandalkan operator kelebihan beban (seperti yang dilakukan Boost), ini adalah proses tingkat kompiler, yang meluas di seluruh bahasa. Antara lain, ini membuatnya mudah untuk mengkonversi aplikasi yang dihitung secara manual menjadi ARC. Boost juga dapat menangani variabel lokal secara berbeda dari ARC, di mana ARC tahu saat variabel lokal tidak lagi digunakan dan dapat dirilis pada saat itu. Saya percaya bahwa dengan Boost Anda masih perlu menentukan dalam beberapa cara bahwa Anda selesai dengan variabel.
Brad Larson

6
Untuk menjawab pertanyaan "apakah ini baru", Delphi telah memiliki penghitungan referensi otomatis untuk string, array dan antarmuka (untuk dukungan COM) selama lebih dari satu dekade. Saya setuju bahwa ini adalah kompromi yang bagus antara lingkungan gc'd dan lingkungan "do it all manual". Saya senang itu ada di ObjC dan LLVM (jadi bahasa lain bisa memanfaatkannya juga).
davidmw

2
@theDmi: "Apakah ARC benar-benar sebuah inovasi?". Penghitungan referensi otomatis ditemukan pada tahun 1960 dan telah digunakan dalam banyak bahasa seperti Python dan Mathematica. Ini tidak digunakan dalam JVM atau CLR karena sangat lambat dan siklus bocor.
Jon Harrop

25

ARC hanya memainkan old retain / release (MRC) dengan kompiler mencari tahu kapan harus memanggil retain / release. Ini akan cenderung memiliki kinerja yang lebih tinggi, penggunaan memori puncak yang lebih rendah, dan kinerja yang lebih dapat diprediksi daripada sistem GC.

Di sisi lain beberapa jenis struktur data tidak dimungkinkan dengan ARC (atau MRC), sementara GC dapat menanganinya.

Sebagai contoh, jika Anda memiliki kelas bernama simpul, dan simpul memiliki NSArray anak-anak, dan satu referensi ke induknya yang "hanya bekerja" dengan GC. Dengan ARC (dan penghitungan referensi manual juga) Anda memiliki masalah. Setiap simpul yang diberikan akan dirujuk dari anak-anaknya dan juga dari orang tuanya.

Suka:

A -> [B1, B2, B3]
B1 -> A, B2 -> A, B3 -> A

Semua baik-baik saja saat Anda menggunakan A (katakanlah melalui variabel lokal).

Ketika Anda selesai dengan itu (dan B1 / B2 / B3), sistem GC pada akhirnya akan memutuskan untuk melihat segala sesuatu yang dapat ditemukan mulai dari stack dan register CPU. Ia tidak akan pernah menemukan A, B1, B2, B3 sehingga akan menyelesaikannya dan mendaur ulang memori ke objek lain.

Ketika Anda menggunakan ARC atau MRC, dan selesai dengan A itu memiliki refcount dari 3 (B1, B2, dan B3 semua referensi itu), dan B1 / B2 / B3 semua akan memiliki jumlah referensi 1 (A's NSArray memegang satu referensi ke setiap). Jadi semua benda itu tetap hidup meskipun tidak ada yang bisa menggunakannya.

Solusi umum adalah memutuskan salah satu dari referensi tersebut harus lemah (tidak berkontribusi pada jumlah referensi). Itu akan berfungsi untuk beberapa pola penggunaan, misalnya jika Anda mereferensikan B1 / B2 / B3 hanya melalui A. Namun dalam pola lain itu gagal. Misalnya jika Anda kadang-kadang akan memegang B1, dan berharap untuk naik kembali melalui pointer orangtua dan menemukan A. Dengan referensi yang lemah jika Anda hanya memegang B1, kaleng (dan biasanya akan) menguap, dan mengambil B2, dan B3 dengan itu.

Terkadang ini bukan masalah, tetapi beberapa cara yang sangat berguna dan alami untuk bekerja dengan struktur data yang kompleks sangat sulit digunakan dengan ARC / MRC.

Jadi ARC menargetkan jenis masalah yang sama dengan target GC. Namun ARC bekerja pada pola penggunaan yang lebih terbatas daripada GC, jadi jika Anda menggunakan bahasa GC (seperti Java) dan mencangkokkan sesuatu seperti ARC ke dalamnya, beberapa program tidak akan berfungsi lagi (atau setidaknya akan menghasilkan banyak memori yang ditinggalkan) , dan dapat menyebabkan masalah pertukaran serius atau kehabisan memori atau ruang swap).

Anda juga dapat mengatakan ARC menempatkan prioritas yang lebih besar pada kinerja (atau mungkin dapat diprediksi) sementara GC menempatkan prioritas yang lebih besar untuk menjadi solusi generik. Akibatnya, GC memiliki tuntutan CPU / memori yang kurang dapat diprediksi, dan kinerja yang lebih rendah (biasanya) dari ARC, tetapi dapat menangani pola penggunaan apa pun. ARC akan bekerja lebih baik untuk banyak pola penggunaan umum, tetapi untuk beberapa pola penggunaan (valid!) Akan jatuh dan mati.


"Di sisi lain beberapa jenis struktur data tidak dimungkinkan dengan ARC" Saya pikir maksud Anda pembersihan otomatis tidak dimungkinkan tanpa petunjuk; jelas, struktur datanya.
Steven Fisher

Tentu, tetapi HANYA pembersihan otomatis objek ObjC tersedia di bawah ARC sehingga "tidak ada pembersihan otomatis" == "tidak ada pembersihan". Saya akan menulis ulang kemudian menjawab ketika saya memiliki lebih banyak waktu.
Stripes

@ Tripes: setara dengan pembersihan manual di ARC adalah pemecahan siklus secara manual, misalnya foo = nil.
Douglas

"[ARC] akan cenderung memiliki kinerja yang lebih tinggi ... ARC menempatkan prioritas yang lebih besar pada kinerja". Saya terkejut membaca bahwa ketika diketahui bahwa penghitungan referensi jauh lebih lambat daripada melacak pengumpulan sampah. flyingfrogblog.blogspot.co.uk/2011/01/...
Jon Harrop

2
Secara teori GC lebih cepat (setiap manipulasi jumlah referensi harus multiprosesor yang koheren, dan ada banyak dari mereka). Dalam praktiknya, satu-satunya sistem GC yang tersedia untuk ObjC jauh lebih lambat. Juga sangat umum bagi sistem GC untuk menghentikan sementara thread secara acak untuk jumlah waktu yang dapat dilihat pengguna (ada beberapa sistem GC waktu nyata, tetapi mereka tidak umum, dan saya pikir mereka memiliki batasan "menarik")
Stripes

4

Sihir

Tetapi lebih khusus ARC bekerja dengan melakukan apa yang akan Anda lakukan dengan kode Anda (dengan perbedaan kecil tertentu). ARC adalah teknologi waktu kompilasi, tidak seperti GC yang runtime dan akan berdampak negatif pada kinerja Anda. ARC akan melacak referensi ke objek untuk Anda dan mensintesis metode retain / release / autorelease sesuai dengan aturan normal. Karena ARC ini juga dapat mengeluarkan hal-hal segera setelah tidak diperlukan lagi, daripada membuangnya ke kolam autorelease murni semata-mata untuk kepentingan konvensi.

Beberapa peningkatan lainnya termasuk meniadakan referensi yang lemah, menyalin blok secara otomatis ke tumpukan, mempercepat di seluruh papan (6x untuk kumpulan autorelease!).

Diskusi yang lebih terperinci tentang bagaimana semua ini bekerja dapat ditemukan di LLVM Docs on ARC.


2
-1 "ARC adalah teknologi waktu kompilasi, tidak seperti GC yang runtime dan akan berdampak negatif pada kinerja Anda". Jumlah referensi ditabrak pada saat run-time yang sangat tidak efisien. Itu sebabnya melacak GC seperti JVM dan .NET jauh lebih cepat.
Jon Harrop

1
@ Jon: Apakah Anda punya bukti tentang ini? Dari bacaan saya sendiri, tampaknya algoritma RC baru biasanya berkinerja baik atau lebih baik daripada M&S GC.
xryl669

1
@ xryl669: Ada penjelasan lengkap di Buku Pegangan GC ( gchandbook.org ). Perhatikan bahwa penelusuran! = M&S.
Jon Harrop

3

Ini sangat bervariasi dari pengumpulan sampah. Pernahkah Anda melihat peringatan yang memberi tahu Anda bahwa Anda mungkin membocorkan objek pada garis yang berbeda? Pernyataan itu bahkan memberi tahu Anda pada baris apa Anda mengalokasikan objek. Ini telah diambil selangkah lebih maju dan sekarang dapat menyisipkan retain/ releasepernyataan di lokasi yang tepat, lebih baik daripada kebanyakan programmer, hampir 100% dari waktu. Kadang-kadang ada beberapa contoh aneh benda yang ditahan yang perlu Anda bantu.


0

Sangat dijelaskan dengan baik oleh dokumentasi pengembang Apple. Baca "Bagaimana ARC Bekerja"

Untuk memastikan bahwa instance tidak hilang saat masih dibutuhkan, ARC melacak berapa banyak properti, konstanta, dan variabel yang saat ini merujuk ke setiap instance kelas. ARC tidak akan membatalkan alokasi instance selama setidaknya satu referensi aktif ke instance tersebut masih ada.

Untuk memastikan bahwa instance tidak hilang saat masih dibutuhkan, ARC melacak berapa banyak properti, konstanta, dan variabel yang saat ini merujuk ke setiap instance kelas. ARC tidak akan membatalkan alokasi instance selama setidaknya satu referensi aktif ke instance tersebut masih ada.

Untuk mengetahui Diff. antara pengumpulan sampah dan ARC: Baca ini


0

ARC adalah fitur kompiler yang menyediakan manajemen objek memori secara otomatis.

Alih-alih Anda harus ingat kapan harus digunakan retain, release, danautorelease , ARC mengevaluasi persyaratan seumur hidup dari objek Anda dan secara otomatis memasukkan panggilan manajemen memori yang sesuai untuk Anda pada waktu kompilasi. Kompiler juga menghasilkan metode dealloc yang sesuai untuk Anda.

Kompiler memasukkan retain/releasepanggilan yang diperlukan pada waktu kompilasi, tetapi panggilan tersebut dijalankan pada saat runtime, sama seperti kode lainnya.

Diagram berikut akan memberi Anda pemahaman yang lebih baik tentang cara kerja ARC.

masukkan deskripsi gambar di sini

Mereka yang baru dalam pengembangan iOS dan tidak memiliki pengalaman kerja pada Objective C. Silakan merujuk dokumentasi Apple untuk Panduan Pemrograman Manajemen Memori Lanjutan untuk pemahaman yang lebih baik tentang manajemen memori.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.