Panduan untuk Java String Pool

1. Ikhtisar

The String objek adalah kelas yang digunakan paling dalam bahasa Jawa.

Dalam artikel singkat ini, kita akan menjelajahi Java String Pool - wilayah memori khusus tempat Strings disimpan oleh JVM .

2. Interning String

Berkat kekekalan Strings di Java, JVM dapat mengoptimalkan jumlah memori yang dialokasikan untuknya dengan hanya menyimpan satu salinan dari setiap String literal di pool . Proses ini disebut interning .

Saat kita membuat variabel String dan menetapkan nilai padanya, JVM mencari kumpulan String dengan nilai yang sama.

Jika ditemukan, compiler Java hanya akan mengembalikan referensi ke alamat memorinya, tanpa mengalokasikan memori tambahan.

Jika tidak ditemukan, itu akan ditambahkan ke pool (interned) dan referensinya akan dikembalikan.

Mari tulis tes kecil untuk memverifikasi ini:

String constantString1 = "Baeldung"; String constantString2 = "Baeldung"; assertThat(constantString1) .isSameAs(constantString2);

3. String Dialokasikan Menggunakan Konstruktor

Saat kita membuat String melalui operator baru , compiler Java akan membuat objek baru dan menyimpannya di ruang heap yang disediakan untuk JVM.

Setiap String yang dibuat seperti ini akan mengarah ke wilayah memori yang berbeda dengan alamatnya sendiri.

Mari kita lihat bagaimana ini berbeda dari kasus sebelumnya:

String constantString = "Baeldung"; String newString = new String("Baeldung"); assertThat(constantString).isNotSameAs(newString);

4. Objek String Literal vs String

Saat kita membuat objek String menggunakan operator new () , itu selalu membuat objek baru di memori heap. Di sisi lain, jika kita membuat objek menggunakan sintaks literal String misalnya "Baeldung", itu mungkin mengembalikan objek yang ada dari kumpulan String, jika sudah ada. Jika tidak, ini akan membuat objek String baru dan dimasukkan ke dalam kumpulan string untuk digunakan kembali di masa mendatang.

Pada level tinggi, keduanya adalah objek String , tetapi perbedaan utamanya berasal dari titik di mana operator new () selalu membuat objek String baru . Juga, ketika kita membuat String menggunakan literal - itu disimpan.

Ini akan jauh lebih jelas ketika kita membandingkan dua objek String yang dibuat menggunakan literal String dan operator baru :

String first = "Baeldung"; String second = "Baeldung"; System.out.println(first == second); // True

Dalam contoh ini, objek String akan memiliki referensi yang sama.

Selanjutnya, mari buat dua objek berbeda menggunakan new dan periksa apakah mereka memiliki referensi yang berbeda:

String third = new String("Baeldung"); String fourth = new String("Baeldung"); System.out.println(third == fourth); // False

Demikian pula, ketika kita membandingkan literal String dengan objek String yang dibuat menggunakan operator new () menggunakan operator ==, itu akan mengembalikan false:

String fifth = "Baeldung"; String sixth = new String("Baeldung"); System.out.println(fifth == sixth); // False

Secara umum, kita harus menggunakan notasi literal String jika memungkinkan . Ini lebih mudah dibaca dan memberi kompiler kesempatan untuk mengoptimalkan kode kita.

5. Interning Manual

Kita bisa secara manual memasukkan String di Java String Pool dengan memanggil metode intern () pada objek yang ingin kita intern.

Memasukkan String secara manual akan menyimpan referensinya di pool, dan JVM akan mengembalikan referensi ini bila diperlukan.

Mari buat kasus uji untuk ini:

String constantString = "interned Baeldung"; String newString = new String("interned Baeldung"); assertThat(constantString).isNotSameAs(newString); String internedString = newString.intern(); assertThat(constantString) .isSameAs(internedString);

6. Pengumpulan Sampah

Sebelum Java 7, JVM menempatkan Java String Pool di ruang PermGen , yang memiliki ukuran tetap - tidak dapat diperluas saat runtime dan tidak memenuhi syarat untuk pengumpulan sampah .

Risiko menyimpan String di PermGen (bukan Heap ) adalah bahwa kita bisa mendapatkan kesalahan OutOfMemory dari JVM jika kita menyimpan terlalu banyak Strings .

Mulai Java 7 dan seterusnya, Java String Pool disimpan di ruang Heap , yang merupakan sampah yang dikumpulkan oleh JVM . Keuntungan dari pendekatan ini adalah berkurangnya risiko kesalahan OutOfMemory karena String yang tidak direferensikan akan dihapus dari kumpulan, sehingga melepaskan memori.

7. Performa dan Optimasi

Di Java 6, satu-satunya pengoptimalan yang dapat kami lakukan adalah meningkatkan ruang PermGen selama pemanggilan program dengan opsi JVM MaxPermSize :

-XX:MaxPermSize=1G

Di Java 7, kami memiliki opsi yang lebih detail untuk memeriksa dan memperluas / mengurangi ukuran kumpulan. Mari kita lihat dua opsi untuk melihat ukuran kolam:

-XX:+PrintFlagsFinal
-XX:+PrintStringTableStatistics

Jika kami ingin meningkatkan ukuran kumpulan dalam hal keranjang, kami dapat menggunakan opsi JVM StringTableSize :

-XX:StringTableSize=4901

Sebelum Java 7u40, ukuran kumpulan default adalah 1009 keranjang tetapi nilai ini tunduk pada beberapa perubahan di versi Java yang lebih baru. Tepatnya, ukuran kumpulan default dari Java 7u40 hingga Java 11 adalah 60013 dan sekarang meningkat menjadi 65536.

Perhatikan bahwa meningkatkan ukuran kumpulan akan menghabiskan lebih banyak memori tetapi memiliki keuntungan karena mengurangi waktu yang diperlukan untuk memasukkan String ke dalam tabel.

8. Catatan Tentang Java 9

Hingga Java 8, Strings secara internal direpresentasikan sebagai larik karakter - char [] , dikodekan dalam UTF-16 , sehingga setiap karakter menggunakan dua byte memori.

Dengan Java 9 representasi baru disediakan, disebut Compact Strings. Format baru ini akan memilih pengkodean yang sesuai antara char [] dan byte [] bergantung pada konten yang disimpan.

Karena representasi String baru akan menggunakan encoding UTF-16 hanya jika diperlukan, jumlah memori heap akan jauh lebih rendah, yang pada gilirannya menyebabkan lebih sedikit overhead Garbage Collector pada JVM.

9. Kesimpulan

Dalam panduan ini, kami menunjukkan bagaimana JVM dan compiler Java mengoptimalkan alokasi memori untuk objek String melalui Java String Pool.

Semua contoh kode yang digunakan dalam artikel ini tersedia di GitHub.