Java Virtual Machine - GC Generasi
Sebagian besar JVM membagi heap menjadi tiga generasi - the young generation (YG), the old generation (OG) and permanent generation (also called tenured generation). Apa alasan dibalik pemikiran seperti itu?
Studi empiris telah menunjukkan bahwa sebagian besar objek yang dibuat memiliki umur yang sangat pendek -
Sumber
https://www.oracle.com
Seperti yang Anda lihat bahwa semakin banyak objek yang dialokasikan dengan waktu, jumlah byte yang bertahan menjadi lebih sedikit (secara umum). Objek Jawa memiliki angka kematian yang tinggi.
Kami akan melihat contoh sederhana. Kelas String di Java tidak dapat diubah. Ini berarti bahwa setiap kali Anda perlu mengubah konten objek String, Anda harus membuat objek baru sama sekali. Misalkan Anda membuat perubahan pada string 1000 kali dalam satu lingkaran seperti yang ditunjukkan pada kode di bawah ini -
String str = “G11 GC”;
for(int i = 0 ; i < 1000; i++) {
str = str + String.valueOf(i);
}
Di setiap loop, kami membuat objek string baru, dan string yang dibuat selama iterasi sebelumnya menjadi tidak berguna (artinya, tidak direferensikan oleh referensi apa pun). Umur T objek itu hanya satu iterasi - mereka akan dikumpulkan oleh GC dalam waktu singkat. Objek berumur pendek tersebut disimpan di area generasi muda di heap. Proses mengumpulkan benda-benda dari generasi muda disebut pengumpulan sampah minor, dan selalu menimbulkan jeda 'stop the world'.
Saat generasi muda mulai terisi, GC melakukan pengumpulan sampah kecil-kecilan. Benda mati dibuang, dan benda hidup dipindahkan ke generasi lama. Utas aplikasi berhenti selama proses ini.
Di sini, kita bisa melihat kelebihan yang ditawarkan oleh desain generasi seperti itu. Generasi muda hanyalah sebagian kecil dari tumpukan dan cepat terisi. Namun pemrosesannya membutuhkan waktu yang jauh lebih sedikit daripada waktu yang dibutuhkan untuk memproses seluruh heap. Jadi, jeda 'stop-dunia' dalam kasus ini jauh lebih singkat, meski lebih sering. Kita harus selalu menargetkan jeda yang lebih pendek daripada yang lebih lama, meskipun mungkin lebih sering. Kami akan membahas ini secara rinci di bagian selanjutnya dari tutorial ini.
Generasi muda terbagi dalam dua ruang - eden and survivor space. Objek yang selamat selama pengumpulan eden dipindahkan ke ruang penyintas, dan mereka yang selamat dari ruang penyintas dipindahkan ke generasi lama. Generasi muda dipadatkan saat dikoleksi.
Saat objek dipindahkan ke generasi lama, pada akhirnya akan terisi, dan harus dikumpulkan dan dipadatkan. Algoritme yang berbeda mengambil pendekatan yang berbeda untuk ini. Beberapa dari mereka menghentikan utas aplikasi (yang menyebabkan jeda 'stop-the-world' yang lama karena generasi lama cukup besar dibandingkan dengan generasi muda), sementara beberapa dari mereka melakukannya secara bersamaan sementara utas aplikasi tetap berjalan. Proses ini disebut GC penuh. Dua kolektor seperti ituCMS and G1.
Mari kita sekarang menganalisis algoritma ini secara rinci.
Serial GC
ini adalah GC default pada mesin kelas klien (mesin prosesor tunggal atau 32b JVM, Windows). Biasanya, GC memiliki banyak multithread, tetapi GC serial tidak. Ini memiliki satu utas untuk memproses heap, dan itu akan menghentikan utas aplikasi setiap kali melakukan GC minor atau GC mayor. Kita dapat memerintahkan JVM untuk menggunakan GC ini dengan menentukan flag:-XX:+UseSerialGC. Jika kita ingin menggunakan beberapa algoritma yang berbeda, tentukan nama algoritma. Perhatikan bahwa generasi lama sepenuhnya dipadatkan selama GC utama.
GC Throughput
GC ini adalah default pada 64b JVM dan mesin multi-CPU. Berbeda dengan GC serial, ia menggunakan banyak utas untuk memproses generasi muda dan tua. Karenanya, GC juga disebutparallel collector. Kita dapat memerintahkan JVM kita untuk menggunakan kolektor ini dengan menggunakan bendera:-XX:+UseParallelOldGC atau -XX:+UseParallelGC(untuk JDK 8 dan seterusnya). Utas aplikasi dihentikan saat ia melakukan pengumpulan sampah besar atau kecil. Seperti kolektor serial, itu sepenuhnya memadatkan generasi muda selama GC utama.
Throughput GC mengumpulkan YG dan OG. Ketika eden telah terisi, kolektor mengeluarkan benda-benda hidup darinya ke dalam OG atau salah satu ruang yang selamat (SS0 dan SS1 pada diagram di bawah). Benda mati dibuang untuk membebaskan ruang yang mereka tempati.
Sebelum GC YG
Setelah GC dari YG
Selama GC penuh, pengumpul throughput mengosongkan seluruh YG, SS0, dan SS1. Setelah operasi, OG hanya berisi objek hidup. Kita harus mencatat bahwa kedua kolektor di atas menghentikan thread aplikasi saat memproses heap. Ini berarti jeda 'stopthe- world' yang lama selama GC utama. Dua algoritme berikutnya bertujuan untuk menghilangkannya, dengan mengorbankan lebih banyak sumber daya perangkat keras -
Kolektor CMS
Itu singkatan dari 'concurrent mark-sweep'. Fungsinya adalah menggunakan beberapa utas latar belakang untuk memindai melalui generasi lama secara berkala dan menyingkirkan objek mati. Namun selama GC minor, thread aplikasi dihentikan. Namun, jeda cukup kecil. Ini membuat CMS menjadi kolektor jeda rendah.
Kolektor ini membutuhkan waktu CPU tambahan untuk memindai melalui heap saat menjalankan thread aplikasi. Lebih lanjut, thread latar belakang hanya mengumpulkan heap dan tidak melakukan pemadatan apa pun. Mereka dapat menyebabkan heap menjadi terfragmentasi. Karena ini terus berlanjut, setelah titik waktu tertentu, CMS akan menghentikan semua thread aplikasi dan memadatkan heap menggunakan satu thread. Gunakan argumen JVM berikut untuk memberi tahu JVM agar menggunakan kolektor CMS -
“XX:+UseConcMarkSweepGC -XX:+UseParNewGC” sebagai argumen JVM untuk memerintahkannya menggunakan kolektor CMS.
Sebelum GC
Setelah GC
Perhatikan bahwa pengumpulan dilakukan secara bersamaan.
G1 GC
Algoritme ini bekerja dengan membagi heap menjadi beberapa wilayah. Seperti kolektor CMS, ini menghentikan thread aplikasi saat melakukan GC minor dan menggunakan thread latar belakang untuk memproses generasi lama sambil tetap menjalankan thread aplikasi. Karena generasi lama terbagi menjadi beberapa daerah, ia terus memadatkan mereka saat memindahkan benda dari satu daerah ke daerah lain. Oleh karena itu, fragmentasi minimal. Anda dapat menggunakan bendera:XX:+UseG1GCuntuk memberi tahu JVM Anda agar menggunakan algoritme ini. Seperti CMS, ini juga membutuhkan lebih banyak waktu CPU untuk memproses heap dan menjalankan thread aplikasi secara bersamaan.
Algoritme ini telah dirancang untuk memproses tumpukan yang lebih besar (> 4G), yang dibagi menjadi beberapa wilayah berbeda. Sebagian dari daerah itu terdiri dari generasi muda, dan sisanya adalah generasi tua. YG dihapus menggunakan secara tradisional - semua utas aplikasi dihentikan dan semua objek yang masih hidup hingga generasi lama atau ruang penyintas.
Perhatikan bahwa semua algoritme GC membagi heap menjadi YG dan OG, dan menggunakan STWP untuk menghapus YG. Proses ini biasanya sangat cepat.