Sebagian besar dengan ARC (Penghitungan Referensi Otomatis), kita tidak perlu memikirkan manajemen memori sama sekali dengan objek Objective-C. Tidak diizinkan membuat NSAutoreleasePool
lagi, namun ada sintaks baru:
@autoreleasepool {
…
}
Pertanyaan saya adalah, mengapa saya membutuhkan ini ketika saya tidak seharusnya merilis / autoreleasing secara manual?
EDIT: Untuk meringkas apa yang saya dapatkan dari semua jawaban dan komentar dengan singkat:
Sintaks Baru:
@autoreleasepool { … }
adalah sintaks baru untuk
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
…
[pool drain];
Lebih penting:
- ARC menggunakan
autorelease
sertarelease
. - Dibutuhkan kolam rilis otomatis untuk melakukannya.
- ARC tidak membuat kumpulan rilis otomatis untuk Anda. Namun:
- Utas utama dari setiap aplikasi Kakao sudah memiliki kumpulan autorelease di dalamnya.
- Ada dua kesempatan di mana Anda mungkin ingin memanfaatkan
@autoreleasepool
:- Ketika Anda berada di utas sekunder dan tidak ada kumpulan pelepasan otomatis, Anda harus membuatnya sendiri untuk mencegah kebocoran, seperti
myRunLoop(…) { @autoreleasepool { … } return success; }
. - Ketika Anda ingin membuat kolam yang lebih lokal, seperti @mattjgalloway telah ditampilkan dalam jawabannya.
- Ketika Anda berada di utas sekunder dan tidak ada kumpulan pelepasan otomatis, Anda harus membuatnya sendiri untuk mencegah kebocoran, seperti
Jawaban:
ARC tidak menghilangkan retensi, rilis, dan autorelease, ARC hanya menambahkan yang diperlukan untuk Anda. Jadi masih ada panggilan untuk mempertahankan, masih ada panggilan untuk melepaskan, masih ada panggilan untuk autorelease dan masih ada kolam rilis otomatis.
Salah satu perubahan lain yang mereka buat dengan compiler Clang 3.0 dan ARC yang baru adalah bahwa mereka diganti
NSAutoReleasePool
dengan@autoreleasepool
direktif kompiler.NSAutoReleasePool
selalu sedikit "objek" khusus dan mereka membuatnya sehingga sintaks menggunakan satu tidak bingung dengan objek sehingga umumnya sedikit lebih sederhana.Jadi pada dasarnya, Anda perlu
@autoreleasepool
karena masih ada kolam rilis otomatis yang perlu dikhawatirkan. Anda tidak perlu khawatir untuk menambahkanautorelease
panggilan.Contoh menggunakan kumpulan rilis otomatis:
Contoh yang sangat dibuat-buat, tentu saja, tetapi jika Anda tidak memiliki bagian
@autoreleasepool
dalamfor
-loop luar maka Anda akan melepaskan 10.000.000 objek kemudian pada bukan 10.000 setiap kali putaran bagian luarfor
-loop.Pembaruan: Lihat juga jawaban ini - https://stackoverflow.com/a/7950636/1068248 - untuk mengapa
@autoreleasepool
tidak ada hubungannya dengan ARC.Pembaruan: Saya melihat bagian dalam dari apa yang terjadi di sini dan menulisnya di blog saya . Jika Anda melihat di sana maka Anda akan melihat apa yang dilakukan ARC dan bagaimana gaya baru
@autoreleasepool
dan bagaimana memperkenalkan lingkup digunakan oleh kompiler untuk menyimpulkan informasi tentang apa yang diperlukan, rilis & autorelease yang diperlukan.sumber
@autoreleasepool
bagi saya juga? Jika saya tidak mengendalikan apa yang akan autoreleased atau dirilis (ARC melakukan itu untuk saya), bagaimana saya harus tahu kapan harus menyiapkan kumpulan autorelease?@autoreleasepool
tidak melepaskan otomatis apa pun. Ini menciptakan kumpulan autorelease, sehingga ketika akhir blok tercapai, objek apa pun yang autorelease oleh ARC saat blok aktif akan dikirim pesan rilis. Panduan Pemrograman Manajemen Memori Tingkat Lanjut Apple menjelaskannya sebagai berikut:sumber
release
pesan tetapi jika jumlah tetap> 1 objek TIDAK akan dibatalkan alokasi.Orang sering salah paham tentang ARC untuk pengumpulan sampah atau sejenisnya. Yang benar adalah, setelah beberapa waktu orang-orang di Apple (berkat proyek llvm dan dentang) menyadari bahwa administrasi memori Objective-C (semua
retains
danreleases
, dll.) Dapat diotomatisasi sepenuhnya pada waktu kompilasi . Ini, hanya dengan membaca kode, bahkan sebelum dijalankan! :)Untuk melakukannya hanya ada satu syarat: Kami HARUS mengikuti aturan , jika tidak, kompiler tidak akan dapat mengotomatiskan proses pada waktu kompilasi. Jadi, untuk memastikan bahwa kita tidak pernah melanggar aturan, kami tidak diperbolehkan secara eksplisit menulis
release
,retain
, dll Mereka panggilan secara otomatis disuntikkan ke dalam kode kami oleh compiler. Oleh karena itu internal kita masih memilikiautorelease
s,retain
,release
, dll Hal ini hanya kita tidak perlu menulis mereka lagi.A of ARC otomatis pada waktu kompilasi, yang jauh lebih baik daripada saat run time seperti pengumpulan sampah.
Kami masih memilikinya
@autoreleasepool{...}
karena tidak melanggar aturan apa pun, kami bebas membuat / menguras kumpulan kami kapan saja kami membutuhkannya :).sumber
Itu karena Anda masih perlu memberikan kompiler dengan petunjuk tentang kapan aman bagi objek autoreleased untuk keluar dari ruang lingkup.
sumber
@autoreleasepool
karena saya tidak tahu apakah ARC mungkin memutuskan untuk melepaskan sesuatu secara otomatis?Dikutip dari https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html :
...
sumber
Diperlukan kumpulan autorelease untuk mengembalikan objek yang baru dibuat dari suatu metode. Misalnya pertimbangkan potongan kode ini:
String yang dibuat dalam metode akan memiliki jumlah tetap satu. Sekarang siapa yang akan menyeimbangkan jumlah tetap itu dengan rilis?
Metodenya sendiri? Tidak mungkin, harus mengembalikan objek yang dibuat, jadi tidak boleh melepaskannya sebelum kembali.
Penelepon metode ini? Penelepon tidak berharap untuk mengambil objek yang perlu dirilis, nama metode tidak menyiratkan bahwa objek baru dibuat, ia hanya mengatakan bahwa suatu objek dikembalikan dan objek yang dikembalikan ini mungkin yang baru yang membutuhkan rilis tetapi mungkin sebagai baik menjadi yang sudah ada yang tidak. Apa metode yang dikembalikan mungkin bahkan tergantung pada beberapa keadaan internal, sehingga penelepon tidak bisa tahu apakah harus melepaskan objek itu dan tidak harus peduli.
Jika penelepon harus selalu melepaskan semua objek yang dikembalikan oleh konvensi, maka setiap objek yang tidak baru dibuat harus selalu disimpan sebelum mengembalikannya dari suatu metode dan itu harus dilepaskan oleh penelepon setelah keluar dari ruang lingkup, kecuali dikembalikan lagi. Ini akan menjadi sangat tidak efisien dalam banyak kasus karena seseorang dapat sepenuhnya menghindari mengubah mempertahankan jumlah dalam banyak kasus jika penelepon tidak akan selalu melepaskan objek yang dikembalikan.
Itu sebabnya ada kolam autorelease, jadi metode pertama sebenarnya akan menjadi
Memanggil
autorelease
objek menambahkannya ke kolam autorelease, tetapi apa artinya itu, menambahkan objek ke kolam autorelease? Ya, itu berarti memberi tahu sistem Anda, " Saya ingin Anda melepaskan objek itu untuk saya tetapi beberapa waktu kemudian, tidak sekarang; ia memiliki jumlah penahanan yang perlu diseimbangkan dengan rilis, jika tidak memori akan bocor tetapi saya tidak bisa melakukannya sendiri sekarang, karena saya perlu objek untuk tetap hidup di luar jangkauan saya saat ini dan penelepon saya tidak akan melakukannya untuk saya juga, itu tidak memiliki pengetahuan bahwa ini perlu dilakukan. Jadi tambahkan ke kolam Anda dan setelah Anda membersihkan itu kolam renang, juga membersihkan objek saya untuk saya. "Dengan ARC, kompiler memutuskan kapan Anda akan menyimpan objek, kapan melepaskan objek, dan kapan menambahkannya ke kumpulan autorelease tetapi masih membutuhkan kehadiran kumpulan autorelease untuk dapat mengembalikan objek yang baru dibuat dari metode tanpa kebocoran memori. Apple baru saja membuat beberapa optimasi bagus untuk kode yang dihasilkan yang kadang-kadang akan menghilangkan kolam autorelease selama runtime. Optimalisasi ini mensyaratkan bahwa keduanya, penelepon dan callee menggunakan ARC (ingat mencampur ARC dan non-ARC adalah legal dan juga didukung secara resmi) dan jika itu sebenarnya kasusnya hanya dapat diketahui saat runtime.
Pertimbangkan Kode ARC ini:
Kode yang dihasilkan oleh sistem, dapat berperilaku seperti kode berikut (yaitu versi aman yang memungkinkan Anda untuk secara bebas mencampur kode ARC dan non-ARC):
(Perhatikan bahwa retain / release dalam pemanggil hanya mempertahankan keamanan defensif, itu tidak sepenuhnya diperlukan, kode akan benar tanpa itu)
Atau bisa berperilaku seperti kode ini, jika keduanya terdeteksi menggunakan ARC saat runtime:
Seperti yang Anda lihat, Apple menghilangkan atuorelease, dengan demikian juga pelepasan objek tertunda ketika kolam hancur, serta keselamatan tetap. Untuk mempelajari lebih lanjut tentang bagaimana itu mungkin dan apa yang sebenarnya terjadi di balik layar, lihat posting blog ini.
Sekarang untuk pertanyaan aktual: Mengapa orang menggunakannya
@autoreleasepool
?Bagi sebagian besar pengembang, hanya ada satu alasan yang tersisa hari ini untuk menggunakan konstruksi ini dalam kode mereka dan itu adalah untuk menjaga jejak memori kecil di mana berlaku. Misalnya pertimbangkan loop ini:
Asumsikan bahwa setiap panggilan
tempObjectForData
dapat membuat yang baruTempObject
yang dikembalikan autorelease. For-loop akan membuat satu juta objek temp ini yang semuanya dikumpulkan dalam autoreleasepool saat ini dan hanya sekali kolam itu dihancurkan, semua objek temp dihancurkan juga. Sampai itu terjadi, Anda memiliki satu juta objek temp ini dalam memori.Jika Anda menulis kode seperti ini sebagai gantinya:
Kemudian kumpulan baru dibuat setiap kali for-loop berjalan dan dihancurkan pada akhir setiap iterasi loop. Dengan cara itu paling banyak satu objek temp sedang nongkrong di memori setiap saat meskipun loop berjalan satu juta kali.
Di masa lalu, Anda sering harus mengelola sendiri autoreleasepools saat mengelola utas (misalnya menggunakan
NSThread
) karena hanya utas utama yang secara otomatis memiliki kumpulan autorelease untuk aplikasi Cocoa / UIKit. Namun ini cukup banyak warisan hari ini karena hari ini Anda mungkin tidak akan menggunakan utas untuk memulai. Anda akan menggunakan GCDDispatchQueue
atau atauNSOperationQueue
keduanya dan keduanya mengelola kumpulan autorelease tingkat atas untuk Anda, dibuat sebelum menjalankan blok / tugas dan dihancurkan setelah selesai dengan itu.sumber
Tampaknya ada banyak kebingungan tentang topik ini (dan setidaknya 80 orang yang mungkin sekarang bingung tentang hal ini dan berpikir mereka perlu menaburkan @autoreleasepool di sekitar kode mereka).
Jika sebuah proyek (termasuk dependensinya) secara eksklusif menggunakan ARC, maka @autoreleasepool tidak perlu digunakan dan tidak akan melakukan apa pun yang berguna. ARC akan menangani pelepasan objek pada waktu yang tepat. Sebagai contoh:
menampilkan:
Setiap objek Pengujian dibatalkan alokasi segera setelah nilai keluar dari ruang lingkup, tanpa menunggu kumpulan autorelease untuk keluar. (Hal yang sama terjadi dengan contoh NSNumber; ini hanya memungkinkan kita mengamati dealloc.) ARC tidak menggunakan autorelease.
Alasan @autoreleasepool masih diizinkan adalah untuk proyek ARC campuran dan non-ARC, yang belum sepenuhnya dialihkan ke ARC.
Jika Anda memanggil kode non-ARC, itu dapat mengembalikan objek autoreleased. Jika demikian, loop di atas akan bocor, karena kumpulan autorelease saat ini tidak akan pernah keluar. Di situlah Anda ingin meletakkan @autoreleasepool di sekitar blok kode.
Tetapi jika Anda telah sepenuhnya membuat transisi ARC, lupakan tentang autoreleasepool.
sumber
+ (Testing *) testing { return [Testing new] }
. Maka Anda akan melihat bahwa dealloc tidak akan dipanggil sampai nanti. Ini diperbaiki jika Anda membungkus bagian dalam loop di@autoreleasepool
blok.+ (Testing *) testing { return [Testing new];} + (void) test { while(true) NSLog(@"p = %p", [self testing]);}
[UIImage imageWithData]
ke dalam persamaan, kemudian, tiba-tiba, saya mulai melihatautorelease
perilaku tradisional , yang membutuhkan@autoreleasepool
untuk menjaga memori puncak ke tingkat yang masuk akal.