ARC: apa itu, prinsip kerja Automatic Reference Counting di iOS

Penulis: IT Sectr Diterbitkan: 2026-03-29 Waktu membaca: 8 mnt

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, sistem manajemen memori kompilator di Swift dan Objective-C
  • Prinsip kerja — setiap objek memiliki penghitung referensi (retain count), saat nol objek segera dibebaskan
  • Kualifikasi — strong, weak, dan unowned menentukan bagaimana referensi memengaruhi penghitung dan siklus hidup objek
  • Perbedaan dari GC — ARC bekerja secara deterministik pada tahap kompilasi, tanpa jeda Stop-The-World dan thread pengumpul latar belakang
  • Retain Cycle — masalah utama ARC: jika dua objek saling merujuk melalui strong, penghitung mereka tidak akan pernah nol

Apa itu ARC?

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.

Cara kerja Automatic Reference Counting

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.

swift
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 vs Garbage Collection: perbedaan utama

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.

KarakteristikARC (Swift/ObjC)GC (Java/Go)
Saat pembebasanDeterministik: segera saat penghitung nolNon-deterministik: pada pengumpulan berikutnya
Jeda eksekusiTidak ada (sisipan retain/release pada kompilasi)Ada jeda Stop-The-World (2–200 ms)
OverheadInkremen/dekremen penghitung setiap referensiPenelusuran graf objek, penandaan, pembebasan
MasalahRetain Cycle (penyelesaian manual)Fragmentasi heap, kebocoran pada referensi terlupa
Thread tambahanTidak diperlukanMemerlukan 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.

Strong, Weak, dan Unowned: kualifikasi referensi di ARC

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

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

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

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.

swift
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.

Masalah umum ARC dan solusinya

Meskipun otomatis, ARC bukanlah obat mujarab. Pengembang menghadapi beberapa masalah umum yang memerlukan pemahaman tentang mekanisme manajemen memori internal.

Retain Cycle dalam Closures

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.

swift
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.

Kinerja retain/release

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

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

Apa perbedaan ARC dengan manajemen memori manual (MRR)?

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.

Bisakah ARC bekerja dengan kode C/C++?

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.

Kapan menggunakan weak dan kapan unowned?

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.

Apa itu tipe eksistensial dan bagaimana pengaruhnya terhadap ARC?

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.

Bagaimana cara memeriksa retain count di Swift?

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

  • ARC — sistem manajemen memori kompilator untuk Swift dan Objective-C yang bekerja melalui penghitungan referensi
  • Prinsip — setiap objek memiliki retain count; saat nol, objek segera dan deterministik dibebaskan
  • Perbedaan dari GC — ARC bekerja tanpa thread latar belakang dan jeda Stop-The-World, tetapi memerlukan kontrol retain cycle
  • Strong — meningkatkan penghitung; weak dan unowned tidak meningkat, tetapi unowned tidak direset saat dealokasi
  • Closures — penyebab utama retain cycle di Swift; capture list [weak self] — solusi standar
  • Autorelease Pool — mekanisme pembebasan tertunda untuk objek sementara di loop dan skenario kustom
  • Diagnostik — Xcode Memory Debugger, Instruments, dan LeakCanary (melalui ObjC bridge) untuk menemukan masalah

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.

Diskusikan proyek

Baca juga