1. Gambaran keseluruhan
The String objek adalah kelas yang paling banyak digunakan dalam bahasa Jawa.
Dalam artikel ringkas ini, kita akan meneroka Java String Pool - kawasan memori khas di mana Strings disimpan oleh JVM .
2. String Interning
Berkat kebolehubahan Strings di Java, JVM dapat mengoptimumkan jumlah memori yang diperuntukkan untuk mereka dengan menyimpan hanya satu salinan setiap String literal di kumpulan . Proses ini dipanggil interning .
Apabila kita membuat pembolehubah String dan memberikan nilai padanya, JVM mencari kumpulan untuk String dengan nilai yang sama.
Sekiranya dijumpai, penyusun Java hanya akan mengembalikan rujukan ke alamat ingatannya, tanpa memperuntukkan memori tambahan.
Sekiranya tidak dijumpai, ia akan ditambahkan ke kolam (intern) dan rujukannya akan dikembalikan.
Mari tulis ujian kecil untuk mengesahkan ini:
String constantString1 = "Baeldung"; String constantString2 = "Baeldung"; assertThat(constantString1) .isSameAs(constantString2);
3. Rentetan yang Diperuntukkan Menggunakan Pembina
Apabila kita membuat String melalui operator baru , penyusun Java akan membuat objek baru dan menyimpannya di ruang timbunan yang disediakan untuk JVM.
Setiap String yang dibuat seperti ini akan menunjuk ke kawasan memori yang berbeza dengan alamatnya sendiri.
Mari lihat bagaimana ini berbeza dengan kes sebelumnya:
String constantString = "Baeldung"; String newString = new String("Baeldung"); assertThat(constantString).isNotSameAs(newString);
4. String Literal vs String Object
Apabila kita membuat objek String menggunakan operator baru () , ia selalu membuat objek baru dalam memori timbunan. Sebaliknya, jika kita membuat objek menggunakan sintaks literal String misalnya "Baeldung", ia mungkin mengembalikan objek yang ada dari kumpulan String, jika sudah ada. Jika tidak, ia akan membuat objek String baru dan dimasukkan ke dalam kumpulan string untuk digunakan kembali di masa depan.
Pada tahap tinggi, kedua-duanya adalah objek String , tetapi perbezaan utama datang dari titik bahawa operator baru () selalu membuat objek String baru . Juga, apabila kita membuat String menggunakan literal - ia di-intern.
Ini akan menjadi lebih jelas apabila kita membandingkan dua objek String yang dibuat menggunakan String literal dan operator baru :
String first = "Baeldung"; String second = "Baeldung"; System.out.println(first == second); // True
Dalam contoh ini, objek String akan mempunyai rujukan yang sama.
Seterusnya, mari buat dua objek yang berbeza menggunakan yang baru dan periksa bahawa mereka mempunyai rujukan yang berbeza:
String third = new String("Baeldung"); String fourth = new String("Baeldung"); System.out.println(third == fourth); // False
Begitu juga, apabila kita membandingkan literal String dengan objek String yang dibuat menggunakan operator baru () menggunakan operator ==, ia akan kembali palsu:
String fifth = "Baeldung"; String sixth = new String("Baeldung"); System.out.println(fifth == sixth); // False
Secara umum, kita harus menggunakan notasi literal String apabila mungkin . Lebih mudah dibaca dan ini memberi peluang kepada penyusun untuk mengoptimumkan kod kami.
5. Interning Manual
Kita secara manual dapat melatih String di Java String Pool dengan memanggil kaedah intern () pada objek yang ingin kita magang.
Memasukkan String secara manual akan menyimpan rujukannya di kolam, dan JVM akan mengembalikan rujukan ini apabila diperlukan.
Mari buat kes ujian 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. Pengutipan Sampah
Sebelum Java 7, JVM menempatkan Java String Pool di ruang PermGen , yang memiliki ukuran tetap - ia tidak dapat dikembangkan pada waktu runtime dan tidak memenuhi syarat untuk pengumpulan sampah .
Risiko magang Strings dalam PermGen (bukannya Heap ) adalah bahawa kita boleh mendapatkan OutOfMemory ralat dari JVM jika kita pelatih terlalu banyak Strings .
Dari Java 7 dan seterusnya, Java String Pool disimpan di ruang Heap , yang merupakan sampah yang dikumpulkan oleh JVM . Kelebihan pendekatan ini ialah penurunan risiko OutOfMemory ralat kerana mempunyai rujukan Strings akan dikeluarkan daripada kolam, dengan itu melepaskan ingatan.
7. Prestasi dan Pengoptimuman
Di Java 6, satu-satunya pengoptimuman yang dapat kita lakukan adalah meningkatkan ruang PermGen selama pemanggilan program dengan pilihan MaxPermSize JVM:
-XX:MaxPermSize=1G
Di Java 7, kami mempunyai pilihan yang lebih terperinci untuk memeriksa dan memperluas / mengurangi ukuran kolam. Mari kita lihat dua pilihan untuk melihat ukuran kolam:
-XX:+PrintFlagsFinal
-XX:+PrintStringTableStatistics
Sekiranya kita ingin meningkatkan ukuran kolam dari segi baldi, kita dapat menggunakan pilihan StringTableSize JVM:
-XX:StringTableSize=4901
Sebelum Java 7u40, ukuran kolam lalai adalah 1009 baldi tetapi nilai ini tunduk pada beberapa perubahan pada versi Java yang lebih baru. Tepatnya, ukuran kolam default dari Java 7u40 hingga Java 11 adalah 60013 dan sekarang meningkat menjadi 65536.
Perhatikan bahawa meningkatkan ukuran kolam akan memakan lebih banyak memori tetapi mempunyai kelebihan untuk mengurangkan masa yang diperlukan untuk memasukkan Strings ke dalam meja.
8. Catatan Tentang Java 9
Sehingga Java 8, String diwakili secara internal sebagai array karakter - char [] , dikodkan dalam UTF-16 , sehingga setiap watak menggunakan dua byte memori.
Dengan Java 9 disediakan representasi baru, yang disebut Compact Strings. Format baru ini akan memilih pengekodan yang sesuai antara char [] dan byte [] bergantung pada kandungan yang disimpan.
Oleh kerana perwakilan String baru akan menggunakan pengekodan UTF-16 hanya apabila perlu, jumlah memori timbunan akan jauh lebih rendah, yang seterusnya menyebabkan Pengumpulan Sampah lebih sedikit di atas JVM.
9. Kesimpulannya
Dalam panduan ini, kami menunjukkan bagaimana JVM dan penyusun Java mengoptimumkan peruntukan memori untuk objek String melalui Java String Pool.
Semua sampel kod yang digunakan dalam artikel boleh didapati di GitHub.