Memahami manajemen memori dalam bahasa pemrograman modern

Halo, Habr! Saya mempersembahkan kepada Anda terjemahan artikel " Demystifying memory management dalam bahasa pemrograman modern " oleh Deepu K Sasidharan.

Dalam seri artikel ini, saya ingin menghilangkan tabir mistisisme atas manajemen memori dalam perangkat lunak (selanjutnya disebut sebagai perangkat lunak) dan mempertimbangkan secara rinci kemungkinan yang ditawarkan oleh bahasa pemrograman modern. Saya harap artikel saya akan membantu pembaca untuk melihat di bawah kap bahasa-bahasa ini dan mempelajari sesuatu yang baru untuk diri mereka sendiri.

Sebuah studi mendalam tentang konsep-konsep manajemen memori memungkinkan Anda untuk menulis perangkat lunak yang lebih efisien, karena gaya dan praktik pengkodean memiliki pengaruh besar pada prinsip-prinsip alokasi memori untuk kebutuhan program.

Bagian 1: Pengantar Manajemen Memori


Manajemen memori adalah serangkaian mekanisme yang memungkinkan Anda untuk mengontrol akses program ke RAM komputer. Topik ini sangat penting dalam pengembangan perangkat lunak dan, pada saat yang sama, menyebabkan kesulitan atau bahkan tetap menjadi kotak hitam bagi banyak programmer.

Untuk apa RAM digunakan?


Ketika sebuah program berjalan pada sistem operasi komputer, ia membutuhkan akses ke memori akses acak (RAM) untuk:

  • unggah bytecode Anda sendiri untuk dieksekusi;
  • menyimpan nilai variabel dan struktur data yang digunakan dalam proses;
  • memuat modul eksternal yang dibutuhkan program untuk menyelesaikan tugas.

Selain ruang yang digunakan untuk memuat bytecode sendiri, program ini menggunakan dua area RAM saat bekerja - stack (tumpukan) dan heap (tumpukan).

Tumpukan


Tumpukan digunakan untuk alokasi memori statis. Ini diatur berdasarkan prinsip "last come - first come" ( LIFO ). Anda dapat membayangkan tumpukan itu sebagai tumpukan buku - hanya boleh berinteraksi dengan buku paling atas: baca atau letakkan yang baru di atasnya.

  • berkat prinsip yang disebutkan, tumpukan memungkinkan Anda untuk dengan cepat melakukan operasi dengan data - semua manipulasi dilakukan dengan "buku teratas dalam tumpukan". Buku ditambahkan ke bagian paling atas jika Anda perlu menyimpan data, atau diambil dari atas jika data perlu dibaca;
  • , , , — ;
  • — . , , — , . , , , . , , , — , ;
  • ;
  • ; ;
  • ;
  • (stack overflow), . , ;
  • , ;



JavaScript. , .


Heap digunakan untuk mengalokasikan memori secara dinamis, namun, tidak seperti stack, data di heap pertama-tama harus ditemukan menggunakan "daftar isi". Orang dapat membayangkan bahwa tumpukan adalah perpustakaan multi-level yang besar, di mana, mengikuti instruksi tertentu, Anda dapat menemukan buku yang diperlukan.

  • operasi pada heap dilakukan agak lebih lambat daripada pada stack, karena mereka memerlukan langkah tambahan untuk mencari data;
  • heap menyimpan data ukuran dinamis, misalnya, daftar di mana Anda dapat menambahkan sejumlah elemen yang berubah-ubah;
  • tumpukan umum untuk semua utas aplikasi;
  • karena sifatnya yang dinamis, heap tidak mudah dalam manajemen dan dengan itu mayoritas dari semua masalah dan kesalahan yang terkait dengan memori muncul. Cara untuk mengatasi masalah ini disediakan oleh bahasa pemrograman;
  • , — ( , ), , , ;
  • (out of memory), , ;
  • , , , .


?


Tidak seperti hard drive, RAM sangat terbatas (walaupun hard drive, tentu saja, juga tidak terbatas). Jika suatu program mengkonsumsi memori tanpa membebaskannya, maka, pada akhirnya, ia akan menyerap semua cadangan yang tersedia dan mencoba untuk melampaui batas memori. Maka ia akan jatuh sendiri, atau, bahkan lebih dramatis, akan menjatuhkan sistem operasi. Oleh karena itu, sangat tidak diinginkan untuk sembrono dengan manipulasi memori dalam pengembangan perangkat lunak.

Pendekatan yang berbeda


Bahasa pemrograman modern mencoba untuk menyederhanakan pekerjaan dengan memori sebanyak mungkin dan menghilangkan sebagian dari sakit kepala dari pengembang. Meskipun beberapa bahasa terhormat masih membutuhkan kontrol manual, sebagian besar masih memberikan pendekatan otomatis yang lebih elegan. Kadang-kadang bahasa menggunakan beberapa pendekatan untuk mengelola memori sekaligus, dan kadang-kadang pengembang bahkan dapat memilih opsi mana yang akan lebih efektif khusus untuk tugasnya (contoh yang baik adalah C ++ ). Mari kita beralih ke tinjauan singkat tentang berbagai pendekatan.

Manajemen memori manual


Bahasa ini tidak menyediakan mekanisme untuk manajemen memori otomatis. Alokasi dan pembebasan memori untuk objek yang dibuat tetap sepenuhnya pada hati nurani pengembang. Contoh dari bahasa tersebut - C . Ini menyediakan sejumlah metode ( malloc , realloc , calloc dan gratis ) untuk mengelola memori - pengembang harus menggunakannya untuk mengalokasikan dan membebaskan memori dalam programnya. Pendekatan ini membutuhkan ketelitian dan perhatian yang besar. Ini juga sangat sulit bagi pemula.

Pengumpul sampah


Pengumpulan sampah adalah proses manajemen memori otomatis pada heap, yang terdiri dari menemukan bagian memori yang tidak terpakai yang sebelumnya ditempati untuk kebutuhan program. Ini adalah salah satu opsi paling populer untuk manajemen memori dalam bahasa pemrograman modern. Rutin pengumpulan sampah biasanya dimulai pada interval waktu yang telah ditentukan dan kebetulan peluncurannya bertepatan dengan proses yang menghabiskan sumber daya, yang mengakibatkan keterlambatan dalam aplikasi. JVM ( Java / Scala / Groovy / Kotlin ), JavaScript , Python , C # , Golang , OCaml danRuby adalah contoh bahasa populer yang menggunakan pemulung.

  • Tandai & Sapu pengumpul sampah : Ini adalah algoritma yang beroperasi dalam dua fase: pertama, ini menandai objek dalam memori yang direferensikan, dan kemudian membebaskan memori dari objek yang belum ditandai. Pendekatan ini digunakan, misalnya, dalam JVM, C #, Ruby, JavaScript, dan Golang. Ada beberapa algoritma pengumpulan sampah yang berbeda untuk dipilih di JVM, dan mesin JavaScript seperti V8 menggunakan algoritma penandaan selain penghitungan tautan. Pengumpul sampah seperti itu dapat dihubungkan dalam C dan C ++ sebagai perpustakaan eksternal.

    Visualisasi algoritma penandaan: objek yang ditautkan oleh tautan ditandai, dan kemudian yang tidak terjangkau dihapus
  • : — , . . , , , , PHP, Perl Python. C++;


(RAII)


RAII adalah idiom perangkat lunak dalam OOP, yang artinya area memori yang dialokasikan untuk suatu objek sangat terikat dengan masa pakainya. Memori dialokasikan di konstruktor dan dibebaskan di destruktor. Pendekatan ini pertama kali diimplementasikan dalam C ++ , dan juga digunakan di Ada dan Rust .

Penghitungan Tautan Otomatis (ARC)


Pendekatan ini sangat mirip dengan pengumpulan sampah dengan penghitungan referensi, namun, alih-alih memulai proses penghitungan pada interval waktu tertentu, instruksi untuk mengalokasikan dan membebaskan memori dimasukkan langsung ke dalam bytecode pada tahap kompilasi. Ketika penghitung referensi mencapai nol, memori dibebaskan sebagai bagian dari aliran program normal.

Penghitungan referensi otomatis masih tidak memungkinkan pemrosesan tautan sirkular dan mengharuskan pengembang untuk menggunakan kata kunci khusus untuk pemrosesan tambahan situasi semacam itu. ARC adalah salah satu fitur dari penerjemah Dentang , oleh karena itu hadir dalam bahasa Objective-C dan Swift . Juga, penghitungan referensi otomatis tersedia untuk digunakan di Rust.dan standar C ++ baru dengan pointer pintar .

Milik


Ini adalah kombinasi dari RAII dengan konsep kepemilikan, ketika setiap nilai dalam memori harus hanya memiliki satu variabel pemilik. Ketika pemilik meninggalkan area eksekusi, memori segera dibebaskan. Kita dapat mengatakan bahwa ini kira-kira seperti menghitung tautan pada tahap kompilasi. Pendekatan ini digunakan dalam Rust dan pada saat yang sama saya tidak dapat menemukan bahasa lain yang akan menggunakan mekanisme serupa.




Artikel ini membahas konsep-konsep dasar di bidang manajemen memori. Setiap bahasa pemrograman menggunakan implementasinya sendiri dari pendekatan dan algoritma yang dioptimalkan untuk berbagai tugas. Pada bagian berikut, kami akan melihat lebih dekat solusi manajemen memori dalam bahasa populer.

Baca juga bagian lain dari seri ini:



Referensi





Jika Anda menyukai artikel ini, silakan tambahkan dan tulis komentar.

Anda dapat berlangganan ke penulis artikel di Twitter dan di LinkedIn .

Ilustrasi:
Visualisasi tumpukan dilakukan dengan menggunakan pythontutor .
Ilustrasi konsep kepemilikan: Link Clark, Tim Rust di bawah Lisensi Berbagi-Serupa Atribusi Creative Commons v3.0 .

Untuk bukti terjemahan, terima kasih khusus kepada Alexander Maksimovsky dan Katerina Shibakova

All Articles