Hai!

Saya pikir Anda tidak akan terlalu terkejut jika saya memberi tahu Anda bahwa komputer Anda memiliki jumlah memori yang terbatas :) Bahkan hard drive — umumnya berkali-kali lebih besar dari penyimpanan RAM — dapat dikemas sesuai kapasitas dengan game favorit Anda, acara TV, dan banyak lagi. Untuk mencegah hal ini terjadi, Anda perlu memantau kondisi memori saat ini dan menghapus file yang tidak perlu dari komputer Anda. Apa hubungannya pemrograman Java dengan semua ini? Semuanya! Lagi pula, ketika mesin Java membuat objek apa pun, ia mengalokasikan memori untuk objek itu.

Dalam program yang sangat besar, puluhan dan ratusan ribu objek dibuat, dan masing-masing memiliki bagian memori yang dialokasikan untuknya. Tapi menurut Anda berapa lama semua objek ini ada? Apakah mereka "hidup" selama program kita berjalan? Tentu saja tidak. Bahkan dengan semua kelebihan objek Java, mereka tidak abadi :) Objek memiliki siklus hidupnya sendiri. Hari ini kita akan beristirahat sejenak dari menulis kode dan melihat proses ini :) Selain itu, sangat penting untuk pemahaman Anda tentang cara kerja program dan cara mengelola sumber daya. Jadi, kapan kehidupan suatu objek dimulai? Seperti seseorang - sejak kelahirannya, yaitu ciptaan.


Cat cat = new Cat(); // Here the lifecycle of our Cat object begins!

Pertama, Java Virtual Machine mengalokasikan jumlah memori yang diperlukan untuk membuat objek. Kemudian itu membuat referensi ke memori itu. Dalam kasus kami, referensi itu disebut cat, jadi kami dapat melacaknya. Kemudian semua variabelnya diinisialisasi, konstruktor dipanggil, dan — ta-da! — objek baru kita menjalani kehidupannya sendiri :)

Umur objek bervariasi, jadi kami tidak dapat memberikan angka pasti di sini. Bagaimanapun, itu hidup untuk beberapa waktu di dalam program dan menjalankan fungsinya. Tepatnya, sebuah objek "hidup" selama ada referensi untuk itu. Segera setelah tidak ada referensi yang tersisa, objek tersebut "mati". Contoh:


public class Car {
  
   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");
       lamborghini = null;

   }

}

Objek mobil Lamborghini Diablo berhenti hidup di baris kedua metode ini main(). Hanya ada satu referensi untuk itu, dan kemudian referensi itu disetel sama dengan null. Karena tidak ada referensi yang tersisa untuk Lamborghini Diablo, memori yang dialokasikan menjadi "sampah". Referensi tidak harus disetel ke nol agar hal ini terjadi:


public class Car {

   String model;

   public Car(String model) {
       this.model = model;
   }

   public static void main(String[] args) {
       Car lamborghini  = new Car("Lamborghini Diablo");

       Car lamborghiniGallardo = new Car("Lamborghini Gallardo");
       lamborghini = lamborghiniGallardo;
   }

}

Di sini kita membuat objek kedua dan kemudian menugaskan objek baru ini ke referensi lamborghini. Sekarang Lamborghini Gallardoobjek tersebut memiliki dua referensi, tetapi Lamborghini Diabloobjek tersebut tidak memilikinya. Itu berarti Diabloobjek tersebut sekarang menjadi sampah. Ini adalah saat mekanisme bawaan Java yang disebut pengumpul sampah (GC) ikut berperan.

Pengumpul sampah adalah mekanisme internal Java yang bertanggung jawab untuk mengosongkan memori, yaitu menghapus objek yang tidak perlu dari memori. Ada alasan bagus mengapa kami memilih gambar robot penyedot debu di sini. Lagi pula, pengumpul sampah bekerja dengan cara yang hampir sama: di latar belakang, ia "berkeliling" di sekitar program Anda, mengumpulkan sampah hampir tanpa usaha dari pihak Anda. Tugasnya adalah menghapus objek yang tidak lagi digunakan dalam program.

Melakukan hal ini membebaskan memori di komputer untuk objek lain. Apakah Anda ingat di awal pelajaran kami mengatakan bahwa dalam kehidupan biasa Anda harus memantau keadaan komputer Anda dan menghapus file yang tidak perlu? Nah, dalam kasus objek Java, pengumpul sampah melakukan ini untuk Anda. Pengumpul sampah berjalan berulang kali saat program Anda berjalan: Anda tidak perlu memanggilnya secara eksplisit atau memberinya perintah, meskipun secara teknis hal ini memungkinkan. Nanti kita akan membicarakannya lebih lanjut dan menganalisis pekerjaannya secara lebih rinci.

Saat pengumpul sampah mencapai objek, tepat sebelum menghancurkan objek, ia memanggil metode khusus — finalize()— pada objek. Metode ini dapat melepaskan sumber daya lain yang digunakan oleh objek. Metode finalize()adalah bagian dari Objectkelas. Artinya, selain equals(), hashCode()dan toString()metode yang Anda temui sebelumnya, setiap objek memiliki metode ini. Ini berbeda dari metode lain karena - bagaimana saya harus meletakkannya - sangat berubah-ubah.

Secara khusus, itu tidak selalu disebut sebelum penghancuran suatu objek. Pemrograman adalah usaha yang tepat. Pemrogram memberi tahu komputer untuk melakukan sesuatu, dan komputer melakukannya. Saya kira Anda sudah terbiasa dengan perilaku ini, jadi pada awalnya mungkin sulit bagi Anda untuk menerima ide berikut ini: "Sebelum penghancuran objek, metode kelas finalize()dipanggil Object. Atau mungkin tidak dipanggil. Itu semua tergantung pada keberuntunganmu!"

Namun, itu benar. Mesin Java itu sendiri menentukan apakah akan memanggil finalize()metode berdasarkan kasus per kasus atau tidak. Misalnya, mari coba jalankan kode berikut sebagai eksperimen:


public class Cat {

   private String name;

   public Cat(String name) {
       this.name = name;
   }

   public Cat() {
   }

   public static void main(String[] args) throws Throwable {
       for (int i = 0 ; i < 1000000; i++) {
           Cat cat = new Cat();
           cat = null; // This is when the first object becomes available to the garbage collector
       }
   }

   @Override
   protected void finalize() throws Throwable {
       System.out.println("Cat object destroyed!");
   }
}

Kami membuat Catobjek dan kemudian di baris kode berikutnya kami menetapkan satu-satunya referensi yang sama dengan nol. Dan kami melakukannya jutaan kali. Kami secara eksplisit mengesampingkan finalize()metode sehingga mencetak string ke konsol jutaan kali (sekali untuk setiap kali menghancurkan objek Cat). Tapi tidak! Tepatnya, itu hanya berjalan 37.346 kali di komputer saya! Artinya, hanya sekali dalam 27 kali mesin Java yang terinstal di mesin saya memutuskan untuk memanggil finalize()metode tersebut.

Dalam kasus lain, pengumpulan sampah terjadi tanpa itu. Coba jalankan kode ini sendiri: kemungkinan besar, Anda akan mendapatkan hasil yang berbeda. Seperti yang Anda lihat, finalize()hampir tidak bisa disebut mitra yang andal :) Jadi, sedikit saran untuk masa depan: jangan mengandalkan metode finalize()untuk membebaskan sumber daya penting. Mungkin JVM akan memanggilnya, atau mungkin tidak. Siapa tahu?

Jika objek Anda masih hidup, ia menyimpan beberapa sumber daya yang sangat penting untuk kinerja, misalnya, koneksi basis data terbuka, lebih baik membuat metode khusus di kelas Anda untuk melepaskannya dan kemudian memanggilnya secara eksplisit saat objek tidak ada lagi. diperlukan. Dengan begitu Anda akan tahu pasti bahwa kinerja program Anda tidak akan menurun. Sejak awal, kami mengatakan bahwa bekerja dengan memori dan membuang sampah sangat penting, dan ini benar. Penanganan sumber daya yang tidak benar dan kesalahpahaman bagaimana objek yang tidak perlu dibersihkan dapat menyebabkan kebocoran memori. Ini adalah salah satu kesalahan pemrograman yang paling terkenal.

Jika pemrogram salah menulis kodenya, memori baru dapat dialokasikan untuk objek yang baru dibuat setiap kali, sementara objek lama yang tidak diperlukan mungkin tidak tersedia untuk dihapus oleh pengumpul sampah. Karena kita membuat analogi dengan penyedot debu robot, bayangkan apa yang terjadi jika, sebelum memulai robot, Anda menyebarkan kaus kaki di sekitar rumah, memecahkan vas kaca, dan meninggalkan balok bangunan Lego di lantai. Robot akan mencoba melakukan tugasnya, tentu saja, tetapi pada titik tertentu ia akan macet.

Agar penyedot debu robot berfungsi dengan baik, Anda harus menjaga lantai dalam kondisi baik dan menyingkirkan apa pun yang tidak dapat ditangani robot. Prinsip yang sama berlaku untuk pengumpul sampah Java. Jika ada banyak objek yang tertinggal dalam program yang tidak dapat dibersihkan (seperti kaus kaki atau balok penyusun Lego untuk penyedot debu robot kami), suatu saat Anda akan kehabisan memori. Dan mungkin bukan hanya program Anda yang akan dibekukan — setiap program lain yang berjalan di komputer mungkin akan terpengaruh. Mereka juga mungkin tidak memiliki cukup memori.

Anda tidak perlu menghafal ini. Anda hanya perlu memahami prinsip di balik cara kerjanya.