Automatic Reference Counting (ARC) — sistem manajemen memori di Swift dan Objective-C yang secara otomatis menghitung jumlah referensi ke setiap objek dan membebaskannya saat penghitung mencapai nol. Menurut Apple Swift Documentation, 2026, ARC tertanam di kompilator dan bekerja pada tahap kompilasi, menyisipkan panggilan retain/release di tempat yang tepat. Tidak seperti Garbage Collection, ARC tidak memerlukan thread pengumpul terpisah dan tidak membuat jeda selama eksekusi aplikasi.
Poin Penting
ARC (Automatic Reference Counting) — adalah mekanisme manajemen memori tingkat kompilator, diperkenalkan oleh Apple di Xcode 4.2 (2011) untuk Objective-C dan diwarisi oleh Swift. Tidak seperti manajemen memori manual (Manual Retain-Release, MRR), ARC sepenuhnya mengotomatiskan panggilan retain, release, dan autorelease, menyisipkannya pada tahap kompilasi tanpa campur tangan pengembang.
ARC bukanlah garbage collector. Ini adalah analisis statis dengan penyisipan kode dinamis: kompilator menganalisis masa hidup objek dan menempatkan retain/release pada titik di mana objek dibuat, disalin, atau keluar dari ruang lingkup. Hasilnya — pembebasan memori deterministik: objek dihapus tepat pada saat tidak ada lagi referensi ke objek tersebut, tanpa penundaan dan jeda.
Menurut WWDC 2011 Session 323, peralihan dari MRR ke ARC mengurangi jumlah bug crash terkait memori sebesar 70% di aplikasi Apple. Pengembang tidak lagi perlu menyeimbangkan retain/release secara manual, yang menghilangkan seluruh kelas kebocoran dan kesalahan double-free.
Setiap objek di memori memiliki penghitung referensi (retain count). Saat objek dibuat, penghitung diatur ke 1. Saat referensi strong baru menunjuk ke objek — penghitung bertambah (retain). Saat referensi strong hilang — penghitung berkurang (release). Saat mencapai nol, objek segera dialokasikan.
Kompilator Swift tidak menyisipkan retain/release pada setiap penugasan — ia menggunakan analisis statis untuk optimasi. Misalnya, jika objek dijamin tidak akan digunakan setelah transfer, kompilator dapat melewatkan release/retain yang berlebihan. Optimasi ini disebut ARC Optimisation.
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) diinisialisasi (retain count: 1)")
}
deinit {
print("\(name) didealokasi")
}
}
func testARC() {
let p = Person(name: "Alice") // retain count = 1
let q = p // retain count = 2
// q keluar dari ruang lingkup
// retain count = 1
// p keluar dari ruang lingkup
// retain count = 0 → deinit
}
Dalam contoh ini terlihat bagaimana ARC mengelola penghitung: saat penugasan q = p, penghitung bertambah, saat q keluar dari ruang lingkup — berkurang. Ketika referensi strong terakhir hilang, deinitializer segera dipanggil. Tidak ada garbage collector yang menunggu — memori segera dibebaskan.
ARC dan Garbage Collection menyelesaikan tugas yang sama — manajemen memori otomatis — tetapi dengan pendekatan yang fundamental berbeda. Pilihan di antara mereka menentukan arsitektur bahasa: Swift (ARC) vs Java/Go (GC). Mari kita lihat perbedaan utama.
| Karakteristik | ARC (Swift/ObjC) | GC (Java/Go) |
|---|---|---|
| Saat pembebasan | Deterministik: segera saat penghitung nol | Non-deterministik: pada pengumpulan berikutnya |
| Jeda eksekusi | Tidak ada (sisipan retain/release pada kompilasi) | Ada jeda Stop-The-World (2–200 ms) |
| Overhead | Inkremen/dekremen penghitung setiap referensi | Penelusuran graf objek, penandaan, pembebasan |
| Masalah | Retain Cycle (penyelesaian manual) | Fragmentasi heap, kebocoran pada referensi terlupa |
| Thread tambahan | Tidak diperlukan | Memerlukan thread garbage collector |
Kompromi utama: ARC memberikan masa hidup objek yang dapat diprediksi dan jeda nol, tetapi membutuhkan pemahaman tentang retain cycle dan pemilihan weak/unowned yang tepat. GC membebaskan dari kekhawatiran ini, tetapi dengan harga jeda non-deterministik dan thread tambahan.
ARC mendefinisikan tiga jenis kualifikasi referensi, yang masing-masing memengaruhi penghitung dan siklus hidup objek secara berbeda. Pemilihan kualifikasi yang tepat adalah dasar kerja aman dengan memori di Swift.
Strong — kualifikasi default. Setiap referensi strong meningkatkan retain count objek sebesar 1. Selama masih ada setidaknya satu referensi strong, objek tetap hidup. Semua properti kelas dan variabel lokal di Swift secara default adalah strong. Referensi strong menciptakan hubungan kepemilikan: objek A memiliki objek B.
Weak — referensi yang tidak meningkatkan retain count. Objek dapat dialokasikan meskipun ada referensi weak yang menunjuk ke objek tersebut. Setelah dealokasi, referensi weak secara otomatis diatur ke nil. Referensi weak selalu dideklarasikan sebagai var dengan tipe opsional (?). Digunakan untuk memutus retain cycle, terutama dalam pola delegate.
Unowned — referensi non-kepemilikan yang, seperti weak, tidak meningkatkan retain count. Namun, referensi unowned tidak diatur ke nil setelah dealokasi — akses ke objek yang telah dibebaskan menyebabkan crash. Unowned digunakan ketika dijamin bahwa objek hidup setidaknya selama objek yang mereferensikannya. Skenario tipikal — closures dan hubungan orangtua-anak dengan masa hidup terjamin.
class Customer {
let name: String
var card: CreditCard? // strong
init(name: String) { self.name = name }
deinit { print("\(name) didealokasi") }
}
class CreditCard {
let number: String
unowned let customer: Customer // unowned — tidak memiliki
init(number: String, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Kartu \(number) didealokasi") }
}
var customer: Customer? = Customer(name: "Bob")
customer?.card = CreditCard(number: "1234", customer: customer!)
customer = nil
// Customer dan CreditCard keduanya dibebaskan — tidak ada retain cycle
Di sini CreditCard menggunakan referensi unowned ke Customer. Customer memiliki kartu (strong), dan kartu tidak memiliki pelanggan (unowned). Saat Customer menjadi nil, kedua objek dibebaskan — retain cycle tidak terjadi. Jika card.customer adalah strong, siklus akan memblokir pembebasan.
Meskipun otomatis, ARC bukanlah obat mujarab. Pengembang menghadapi beberapa masalah umum yang memerlukan pemahaman tentang mekanisme manajemen memori internal.
Closures di Swift menangkap variabel eksternal melalui referensi strong. Jika closure ditugaskan ke properti kelas dan menangkap self — terjadilah retain cycle: kelas memegang closure, closure memegang self. Solusinya — capture list dengan weak atau unowned.
class NetworkManager {
var completionHandler: ((Data?) -> Void)?
var data: Data?
func fetchData() {
completionHandler = { [weak self] result in
guard let self else { return }
self.data = result
self.processResult()
}
}
func processResult() { }
}
Capture list [weak self] membuat referensi weak ke self di dalam closure. Ini memutus potensi retain cycle. Guard let self memastikan objek masih hidup sebelum mengeksekusi kode. weak self — praktik standar untuk closures asinkron di Swift.
Meskipun retain/release adalah operasi ringan, seringnya inkremen/dekremen penghitung di loop panas menghasilkan overhead. Di Swift 5.9+, kompilator menggunakan optimasi, di mana retain/release berlebihan dihapus jika analisator dapat membuktikan keamanan. Namun, di Objective-C retain/release masih bisa menjadi hambatan dalam skenario beban tinggi dengan jutaan panggilan per detik.
Autorelease Pool — mekanisme release tertunda, digunakan di Objective-C dan beberapa skenario Swift. Objek ditempatkan di pool dan mendapatkan release saat pool dikeringkan. Dalam loop dengan banyak objek sementara (misalnya, parsing JSON), membuat autoreleasepool sendiri mengurangi konsumsi puncak memori operasional.
Pertanyaan yang Sering Diajukan
Dalam manajemen manual (MRR), pengembang secara eksplisit memanggil retain, release, dan autorelease. ARC menyisipkan panggilan ini secara otomatis pada tahap kompilasi, menghilangkan risiko double-free, kebocoran karena release terlupa, dan kesalahan penyeimbangan retain/release.
ARC hanya mengelola objek Objective-C dan kelas Swift. Untuk struktur dan pointer C/C++, ARC tidak diterapkan — objek-objek ini dikelola secara manual atau melalui smart pointer C++ (shared_ptr, unique_ptr). Objek Core Foundation (CFString, CGColor) juga tidak termasuk dalam ARC.
weak — ketika objek dapat dialokasi lebih awal dari objek yang mereferensikannya (delegates, closures asinkron). unowned — ketika dijamin objek hidup setidaknya selama objek yang mereferensikannya (orangtua-anak, di mana anak tidak dapat ada tanpa orangtua). Jika tidak yakin — pilih weak.
Tipe eksistensial (protocol as type) di Swift membungkus nilai dalam wadah khusus (existential container). Ini meningkatkan jumlah retain/release di batas protokol. Di Swift 5.7+, opaque result types dan parameter some mengurangi overhead dengan menghilangkan wadah.
Tidak ada API langsung untuk membaca retain count di Swift — ini dianggap sebagai detail implementasi. Untuk diagnostik, gunakan Instruments (Allocations, Leaks) atau Memory Debugger di Xcode. Alat-alat ini menunjukkan jumlah instance hidup dari kelas dan rantai retensi.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga