Apakah string Java benar-benar tidak berubah?


399

Kita semua tahu bahwa Stringitu tidak dapat diubah di Jawa, tetapi periksa kode berikut:

String s1 = "Hello World";  
String s2 = "Hello World";  
String s3 = s1.substring(6);  
System.out.println(s1); // Hello World  
System.out.println(s2); // Hello World  
System.out.println(s3); // World  

Field field = String.class.getDeclaredField("value");  
field.setAccessible(true);  
char[] value = (char[])field.get(s1);  
value[6] = 'J';  
value[7] = 'a';  
value[8] = 'v';  
value[9] = 'a';  
value[10] = '!';  

System.out.println(s1); // Hello Java!  
System.out.println(s2); // Hello Java!  
System.out.println(s3); // World  

Mengapa program ini beroperasi seperti ini? Dan mengapa nilai s1dans2 berubah, tetapi tidak s3?


394
Anda dapat melakukan segala macam trik bodoh dengan refleksi. Tapi Anda pada dasarnya melanggar stiker "garansi batal jika dihapus" di kelas begitu Anda melakukannya.
cHao

16
@DarshanPatel menggunakan SecurityManager untuk menonaktifkan refleksi
Sean Patrick Floyd

39
Jika Anda benar-benar ingin mengacaukan hal-hal yang dapat Anda lakukan sehingga (Integer)1+(Integer)2=42dengan mengacaukan autoboxing cache; (Disgruntled-Bomb-Java-Edition) ( thedailywtf.com/Articles/Disgruntled-Bomb-Java-Edition.aspx )
Richard Tingle

15
Anda mungkin terhibur dengan jawaban ini yang saya tulis hampir 5 tahun yang lalu stackoverflow.com/a/1232332/27423 - ini tentang daftar yang tidak dapat diubah dalam C # tetapi pada dasarnya hal yang sama: bagaimana saya dapat menghentikan pengguna dari memodifikasi data saya? Dan jawabannya adalah, Anda tidak bisa; refleksi membuatnya sangat mudah. Salah satu bahasa utama yang tidak memiliki masalah ini adalah JavaScript, karena tidak memiliki sistem refleksi yang dapat mengakses variabel lokal di dalam penutupan, sehingga privat benar-benar berarti privat (walaupun tidak ada kata kunci untuk itu!)
Daniel Earwicker

49
Adakah yang membaca pertanyaan sampai akhir ?? Pertanyaannya adalah, izinkan saya ulangi: "Mengapa program ini beroperasi seperti ini? Mengapa nilai s1 dan s2 berubah dan tidak berubah untuk s3?" Pertanyaannya BUKAN mengapa s1 dan s2 berubah! Pertanyaannya adalah: MENGAPA s3 tidak diubah?
Roland Pihlakas

Jawaban:


403

String tidak dapat diubah * tetapi ini hanya berarti Anda tidak dapat mengubahnya menggunakan API publiknya.

Apa yang Anda lakukan di sini adalah menghindari API normal, menggunakan refleksi. Dengan cara yang sama, Anda dapat mengubah nilai enum, mengubah tabel pencarian yang digunakan dalam bilangan bulat Integer dll.

Sekarang, alasan s1dan s2nilai perubahan, adalah bahwa keduanya merujuk ke string yang diinternir yang sama. Kompiler melakukan ini (sebagaimana disebutkan oleh jawaban lain).

Alasannya s3sebenarnya tidak sedikit mengejutkan bagi saya, karena saya pikir itu akan berbagi valuearray ( itu dalam versi Java yang lebih lama , sebelum Java 7u6). Namun, melihat kode sumber String, kita dapat melihat bahwa valuearray karakter untuk substring sebenarnya disalin (menggunakan Arrays.copyOfRange(..)). Inilah mengapa itu tidak berubah.

Anda dapat menginstal SecurityManager, untuk menghindari kode berbahaya untuk melakukan hal-hal seperti itu. Tetapi perlu diingat bahwa beberapa perpustakaan bergantung pada penggunaan trik-trik refleksi semacam ini (biasanya alat ORM, perpustakaan AOP dll).

*) Saya awalnya menulis bahwa Strings tidak benar-benar abadi, hanya "tidak dapat diubah". Ini mungkin menyesatkan dalam implementasi saat ini String, di mana valuearray memang ditandai private final. Namun, masih perlu dicatat bahwa tidak ada cara untuk mendeklarasikan array di Java sebagai tidak dapat diubah, jadi harus berhati-hati untuk tidak mengeksposnya di luar kelasnya, bahkan dengan pengubah akses yang tepat.


Karena topik ini tampaknya sangat populer, inilah beberapa saran untuk bacaan lebih lanjut: Refleksi Madness Heinz Kabutz dari JavaZone 2009, yang mencakup banyak masalah di OP, bersama dengan refleksi lain ... well ... kegilaan.

Ini mencakup mengapa ini kadang berguna. Dan mengapa, sebagian besar waktu, Anda harus menghindarinya. :-)


7
Sebenarnya, Stringmagang adalah bagian dari JLS ( "string literal selalu merujuk ke instance yang sama dari class String" ). Tapi saya setuju, bukan praktik yang baik untuk mengandalkan detail implementasi Stringkelas.
HaraldK

3
Mungkin alasan mengapa substringsalinan daripada menggunakan "bagian" dari array yang ada, adalah sebaliknya jika saya memiliki string besar sdan mengeluarkan substring kecil yang dipanggil t, dan saya kemudian ditinggalkan stetapi disimpan t, maka array besar akan tetap hidup (bukan sampah yang dikumpulkan). Jadi mungkin lebih alami untuk setiap nilai string untuk memiliki array terkait sendiri?
Jeppe Stig Nielsen

10
Berbagi array antara string dan substringnya juga menyiratkan bahwa setiap String instance harus membawa variabel untuk mengingat offset ke array dan panjang yang dimaksud. Itu overhead untuk tidak mengabaikan mengingat jumlah total string dan rasio khas antara string normal dan substring dalam suatu aplikasi. Karena mereka harus dievaluasi untuk setiap operasi string, itu berarti memperlambat setiap operasi string hanya untuk kepentingan satu operasi saja, sebuah substring yang murah.
Holger

2
@ Holger - Ya, pemahaman saya adalah bahwa bidang offset dijatuhkan di JVM terbaru Dan bahkan ketika itu ada itu tidak sering digunakan.
Hot Licks

2
@supercat: tidak masalah apakah Anda memiliki kode asli atau tidak, memiliki implementasi berbeda untuk string dan substring dalam JVM yang sama atau memiliki byte[]string untuk string ASCII dan char[]bagi yang lain menyiratkan bahwa setiap operasi harus memeriksa jenis string yang sebelum Pengoperasian. Ini menghambat pengurutan kode ke dalam metode menggunakan string yang merupakan langkah pertama dari optimasi lebih lanjut menggunakan informasi konteks pemanggil. Ini dampak besar.
Holger

93

Di Jawa, jika dua variabel primitif string diinisialisasi ke literal yang sama, itu menetapkan referensi yang sama untuk kedua variabel:

String Test1="Hello World";
String Test2="Hello World";
System.out.println(test1==test2); // true

inisialisasi

Itulah alasan perbandingan kembali benar. String ketiga dibuat dengan menggunakan substring()yang membuat string baru alih-alih menunjuk ke yang sama.

sub string

Saat Anda mengakses string menggunakan refleksi, Anda mendapatkan pointer aktual:

Field field = String.class.getDeclaredField("value");
field.setAccessible(true);

Jadi perubahan ini akan mengubah string yang memegang pointer ke sana, tetapi karena s3dibuat dengan string baru karena substring()itu tidak akan berubah.

perubahan


Ini hanya berfungsi untuk literal dan merupakan optimasi waktu kompilasi.
SpacePrez

2
@ Zaphod42 Tidak benar. Anda juga dapat menelepon internsecara manual pada String non-literal dan menuai manfaatnya.
Chris Hayes

Catatan, meskipun: Anda ingin menggunakan secara internbijaksana. Menginternir segala sesuatu tidak banyak menguntungkan Anda, dan dapat menjadi sumber dari beberapa momen menggaruk kepala saat Anda menambahkan refleksi ke dalam campuran.
cao

Test1dan Test1tidak konsisten dengan test1==test2dan tidak mengikuti konvensi penamaan java.
c0der

50

Anda menggunakan refleksi untuk menghindari kekekalan String - ini adalah bentuk "serangan".

Ada banyak contoh yang dapat Anda buat seperti ini (misalnya Anda bahkan dapat membuat Voidinstance objek juga), tetapi itu tidak berarti bahwa String tidak "tidak dapat diubah".

Ada kasus penggunaan di mana jenis kode ini dapat digunakan untuk keuntungan Anda dan menjadi "pengkodean yang baik", seperti membersihkan kata sandi dari memori pada saat yang paling dini (sebelum GC) .

Tergantung pada manajer keamanan, Anda mungkin tidak dapat mengeksekusi kode Anda.


30

Anda menggunakan refleksi untuk mengakses "detail implementasi" objek string. Kekekalan adalah fitur antarmuka publik dari suatu objek.


24

Pengubah visibilitas dan final (yaitu ketidakmampuan) bukan merupakan ukuran terhadap kode berbahaya di Jawa; mereka hanyalah alat untuk melindungi dari kesalahan dan untuk membuat kode lebih dapat dipertahankan (salah satu nilai jual besar dari sistem). Itulah sebabnya Anda dapat mengakses detail implementasi internal seperti array char dukungan untuk Stringmelalui refleksi.

Efek kedua yang Anda lihat adalah bahwa semua Stringberubah sementara sepertinya Anda hanya berubah s1. Ini adalah properti tertentu dari Java String literal yang secara otomatis diinternir, yaitu di-cache. Dua String literal dengan nilai yang sama sebenarnya akan menjadi objek yang sama. Ketika Anda membuat sebuah String dengan newitu tidak akan diinternir secara otomatis dan Anda tidak akan melihat efek ini.

#substringhingga baru-baru ini (Java 7u6) bekerja dengan cara yang serupa, yang akan menjelaskan perilaku dalam versi asli pertanyaan Anda. Itu tidak membuat array char backing baru tetapi menggunakan kembali dari String asli; itu hanya menciptakan objek String baru yang menggunakan offset dan panjang untuk menyajikan hanya sebagian dari array itu. Ini umumnya berfungsi sebagai String tidak dapat diubah - kecuali Anda menghindarinya. Properti ini dari#substring juga berarti bahwa seluruh String asli tidak dapat berupa sampah yang dikumpulkan ketika substring yang lebih pendek dibuat darinya masih ada.

Pada Java saat ini dan versi pertanyaan Anda saat ini tidak ada perilaku aneh #substring.


2
Sebenarnya, pengubah visibilitas yang (atau setidaknya berada) dimaksudkan sebagai terhadap resiko perlindungan kode berbahaya - Namun, Anda perlu menetapkan SecurityManager (System.setSecurityManager ()) untuk mengaktifkan perlindungan. Seberapa amankah ini sebenarnya adalah pertanyaan lain ...
sleske

2
Layak mendapat upvote karena Anda menekankan bahwa pengubah akses tidak dimaksudkan untuk 'melindungi' kode. Ini tampaknya banyak disalahpahami di Jawa dan .NET. Meskipun komentar sebelumnya memang bertentangan; Saya tidak tahu banyak tentang Java, tetapi dalam. NET ini tentu benar. Dalam kedua bahasa, pengguna tidak boleh menganggap ini membuat kode mereka anti-peretasan.
Tom W

Tidak mungkin untuk melanggar kontrak finalbahkan melalui refleksi. Juga, sebagaimana disebutkan dalam jawaban lain, karena Java 7u6, #substringtidak membagikan array.
ntoskrnl

Sebenarnya, perilaku finaltelah berubah dari waktu ke waktu ...: -O Menurut pembicaraan "Reflection Madness" oleh Heinz saya diposting di utas lainnya, finalberarti final di JDK 1.1, 1.3 dan 1.4, tetapi dapat dimodifikasi menggunakan refleksi menggunakan 1.2 selalu , dan dalam 1,5 dan 6 dalam banyak kasus ...
haraldK

1
finalbidang dapat diubah melalui nativekode seperti yang dilakukan oleh kerangka kerja Serialisasi ketika membaca bidang contoh serial serta System.setOut(…)yang memodifikasi System.outvariabel akhir . Yang terakhir adalah fitur yang paling menarik karena refleksi dengan penggantian akses tidak dapat mengubah static finalbidang.
Holger

11

String immutability berasal dari perspektif antarmuka. Anda menggunakan refleksi untuk memintas antarmuka dan secara langsung memodifikasi internal instance String.

s1dan s2keduanya diubah karena keduanya ditugaskan ke instance String "intern" yang sama. Anda dapat menemukan sedikit lebih banyak tentang bagian itu dari artikel ini tentang kesetaraan string dan magang. Anda mungkin terkejut mengetahui bahwa dalam kode sampel Anda,s1 == s2 kembali true!


10

Versi Java mana yang Anda gunakan? Dari Java 1.7.0_06, Oracle telah mengubah representasi internal String, terutama substring.

Mengutip dari Oracle Tunes Internal String Representation Java :

Dalam paradigma baru, bidang offset dan hitung String telah dihapus, sehingga substring tidak lagi berbagi nilai karakter yang mendasarinya.

Dengan perubahan ini, itu bisa terjadi tanpa refleksi (???).


2
Jika OP menggunakan Sun / Oracle JRE yang lebih lama, pernyataan terakhir akan mencetak "Java!" (saat ia secara tidak sengaja diposting). Ini hanya memengaruhi pembagian array nilai antara string dan sub string. Anda masih tidak dapat mengubah nilai tanpa trik, seperti refleksi.
HaraldK

7

Sebenarnya ada dua pertanyaan di sini:

  1. Apakah string benar-benar tidak berubah?
  2. Mengapa s3 tidak diubah?

Ke poin 1: Kecuali untuk ROM tidak ada memori yang tidak dapat diubah di komputer Anda. Saat ini bahkan ROM terkadang dapat ditulis. Selalu ada beberapa kode di suatu tempat (apakah itu kernel atau kode asli yang menghindari lingkungan terkelola Anda) yang dapat menulis ke alamat memori Anda. Jadi, dalam "kenyataan", tidak, mereka tidak mutlak abadi.

Ke poin 2: Ini karena substring mungkin mengalokasikan contoh string baru, yang kemungkinan menyalin array. Dimungkinkan untuk menerapkan substring sedemikian rupa sehingga tidak akan melakukan salinan, tetapi itu tidak berarti demikian. Ada pengorbanan yang terlibat.

Sebagai contoh, haruskah memegang referensi yang reallyLargeString.substring(reallyLargeString.length - 2)menyebabkan sejumlah besar memori tetap hidup, atau hanya beberapa byte?

Itu tergantung pada bagaimana substring diimplementasikan. Salinan yang dalam akan menjaga lebih sedikit memori yang hidup, tetapi akan berjalan sedikit lebih lambat. Salinan dangkal akan membuat lebih banyak memori hidup, tetapi akan lebih cepat. Menggunakan salinan yang dalam juga dapat mengurangi fragmentasi tumpukan, karena objek string dan buffernya dapat dialokasikan dalam satu blok, sebagai lawan dari 2 alokasi tumpukan terpisah.

Bagaimanapun, sepertinya JVM Anda memilih untuk menggunakan salinan yang dalam untuk panggilan substring.


3
ROM asli sama abadi dengan cetak foto yang terbungkus plastik. Pola diatur secara permanen ketika wafer (atau cetak) dikembangkan secara kimia. Memori yang dapat diubah secara listrik, termasuk chip RAM , dapat berperilaku sebagai ROM "benar" jika sinyal kontrol yang diperlukan untuk menulisnya tidak dapat dialiri energi tanpa menambahkan koneksi listrik tambahan ke sirkuit di mana ia dipasang. Sebenarnya tidak jarang perangkat yang dibenamkan memasukkan RAM yang diatur di pabrik dan dikelola oleh baterai cadangan, dan yang isinya perlu dimuat ulang oleh pabrik jika batal gagal.
supercat

3
@supercat: Komputer Anda bukan salah satu dari sistem yang disematkan. :) ROM dengan kabel yang benar belum umum di PC selama satu atau dua dekade; semuanya EEPROM dan flash hari ini. Pada dasarnya setiap alamat yang terlihat oleh pengguna yang mengacu pada memori, mengacu pada memori yang berpotensi dapat ditulis.
cHao

@ cHao: Banyak chip flash memungkinkan bagian-bagiannya dilindungi penulisan dengan cara yang, jika bisa dibatalkan sama sekali, akan membutuhkan penerapan voltase yang berbeda dari yang diperlukan untuk operasi normal (motherboard mana yang tidak akan dilengkapi untuk melakukan). Saya berharap motherboard menggunakan fitur itu. Lebih lanjut, saya tidak yakin tentang komputer saat ini, tetapi secara historis beberapa komputer telah memiliki wilayah RAM yang dilindungi dari penulisan selama tahap boot dan hanya bisa tidak dilindungi oleh reset (yang akan memaksa eksekusi dimulai dari ROM).
supercat

2
@supercat Saya pikir Anda kehilangan inti topik, yaitu string yang disimpan dalam RAM, tidak akan pernah benar-benar berubah.
Scott Wisniewski

5

Untuk menambah jawaban @ haraldK - ini adalah peretasan keamanan yang dapat menyebabkan dampak serius pada aplikasi.

Hal pertama adalah modifikasi string konstan yang disimpan dalam String Pool. Ketika string dideklarasikan sebagai a String s = "Hello World";, string ditempatkan ke dalam kumpulan objek khusus untuk digunakan kembali secara potensial. Masalahnya adalah bahwa kompiler akan menempatkan referensi ke versi yang dimodifikasi pada waktu kompilasi dan setelah pengguna memodifikasi string yang disimpan dalam kumpulan ini saat runtime, semua referensi dalam kode akan menunjuk ke versi yang dimodifikasi. Ini akan menghasilkan bug berikut:

System.out.println("Hello World"); 

Akan dicetak:

Hello Java!

Ada masalah lain yang saya alami ketika saya menerapkan perhitungan berat atas string berisiko tersebut. Ada bug yang terjadi pada 1 dari 10.000 kali selama perhitungan yang membuat hasilnya tidak dapat ditentukan. Saya dapat menemukan masalah dengan mematikan JIT - Saya selalu mendapatkan hasil yang sama dengan JIT dimatikan. Dugaan saya adalah bahwa alasannya adalah peretasan keamanan String ini yang mematahkan beberapa kontrak optimasi JIT.


Ini mungkin masalah keamanan benang yang ditutupi oleh waktu eksekusi yang lebih lambat dan konkurensi yang lebih sedikit tanpa JIT.
Ted Pennings

@TedPennings Dari uraian saya, saya hanya tidak ingin membahas terlalu banyak. Saya benar-benar menghabiskan beberapa hari mencoba melokalkannya. Itu adalah algoritma single-threaded yang menghitung jarak antara dua teks yang ditulis dalam dua bahasa yang berbeda. Saya menemukan dua kemungkinan perbaikan untuk masalah ini - satu untuk mematikan JIT dan yang kedua adalah menambahkan no-op String.format("")di dalam salah satu loop internal. Ada kemungkinan untuk itu menjadi beberapa-lain-kemudian-masalah JIT-kegagalan, tapi saya percaya itu JIT, karena masalah ini tidak pernah direproduksi lagi setelah menambahkan no-op ini.
Andrey Chaschev

Saya melakukan ini dengan versi awal JDK ~ 7u9, jadi bisa jadi itu.
Andrey Chaschev

1
@Andrey Chaschev: "Saya menemukan dua kemungkinan perbaikan untuk masalah ini" ... perbaikan ketiga yang mungkin, bukan untuk meretas bagian Stringdalam, tidak masuk ke pikiran Anda?
Holger

1
@Ted Pennings: masalah keamanan thread dan masalah JIT seringkali sama. JIT diizinkan untuk menghasilkan kode yang bergantung pada finaljaminan keselamatan ulir bidang yang rusak saat memodifikasi data setelah konstruksi objek. Jadi Anda bisa melihatnya sebagai masalah JIT atau masalah MT sesuka Anda. Masalah sebenarnya adalah meretas Stringdan memodifikasi data yang diharapkan tidak berubah.
Holger

5

Menurut konsep pooling, semua variabel String yang berisi nilai yang sama akan mengarah ke alamat memori yang sama. Oleh karena itu s1 dan s2, keduanya mengandung nilai yang sama "Hello World", akan mengarah ke lokasi memori yang sama (katakanlah M1).

Di sisi lain, s3 berisi "Dunia", maka itu akan menunjuk ke alokasi memori yang berbeda (katakanlah M2).

Jadi sekarang yang terjadi adalah bahwa nilai S1 sedang diubah (dengan menggunakan nilai char []). Jadi nilai di lokasi memori M1 yang ditunjukkan oleh s1 dan s2 telah berubah.

Oleh karena itu, lokasi memori M1 telah dimodifikasi yang menyebabkan perubahan nilai s1 dan s2.

Tetapi nilai lokasi M2 tetap tidak berubah, karenanya s3 berisi nilai asli yang sama.


5

Alasan s3 tidak benar-benar berubah adalah karena di Jawa ketika Anda melakukan substring, array karakter nilai untuk substring disalin secara internal (menggunakan Arrays.copyOfRange ()).

s1 dan s2 adalah sama karena di Jawa keduanya merujuk ke string yang diinternir yang sama. Ini dengan desain di Jawa.


2
Bagaimana jawaban ini menambahkan sesuatu ke jawaban sebelum Anda?
Gray

Perhatikan juga bahwa ini adalah perilaku yang cukup baru, dan tidak dijamin oleh spesifikasi apa pun.
Paŭlo Ebermann

Implementasi String.substring(int, int)diubah dengan Java 7u6. Sebelum 7u6, JVM hanya akan menyimpan pointer ke asli String's char[]bersama dengan indeks dan panjang. Setelah 7u6, ia menyalin substring ke baru. StringAda pro dan kontra.
Eric Jablow

2

String tidak dapat diubah, tetapi melalui refleksi Anda diizinkan untuk mengubah kelas String. Anda baru saja mendefinisikan ulang kelas String sebagai bisa berubah secara real-time. Anda dapat mendefinisikan kembali metode menjadi publik atau pribadi atau statis jika Anda inginkan.


2
Jika Anda mengubah visibilitas bidang / metode itu tidak berguna karena pada waktu kompilasi mereka bersifat pribadi
Bohemian

1
Anda dapat mengubah aksesibilitas pada metode tetapi Anda tidak dapat mengubah status publik / pribadi mereka dan Anda tidak dapat membuatnya menjadi statis.
Gray

1

[Penafian ini adalah gaya jawaban yang sengaja dikemukakan pendapat karena saya merasa lebih "jangan lakukan ini di rumah anak-anak" jawaban diperlukan]

Dosa adalah garis field.setAccessible(true); yang mengatakan melanggar api publik dengan mengizinkan akses ke bidang pribadi. Itulah lubang keamanan raksasa yang dapat dikunci dengan mengkonfigurasi manajer keamanan.

Fenomena dalam pertanyaan ini adalah detail implementasi yang tidak akan pernah Anda lihat ketika tidak menggunakan baris kode berbahaya tersebut untuk melanggar pengubah akses melalui refleksi. Jelas dua (biasanya) string yang tidak dapat diubah dapat berbagi array char yang sama. Apakah substring berbagi array yang sama tergantung pada apakah substring dapat dan apakah pengembang berpikir untuk membagikannya. Biasanya ini adalah detail implementasi yang tidak terlihat yang seharusnya tidak perlu Anda ketahui kecuali Anda memotret pengubah akses melalui kepala dengan baris kode tersebut.

Ini bukan ide yang baik untuk mengandalkan detail yang tidak bisa dialami tanpa melanggar pengubah akses menggunakan refleksi. Pemilik kelas itu hanya mendukung API publik normal dan bebas untuk membuat perubahan implementasi di masa mendatang.

Setelah mengatakan semua itu, baris kode benar-benar sangat berguna ketika Anda memegang pistol di kepala Anda dan memaksa Anda untuk melakukan hal-hal berbahaya seperti itu. Menggunakan pintu belakang itu biasanya merupakan bau kode yang perlu Anda tingkatkan ke kode perpustakaan yang lebih baik di mana Anda tidak perlu berbuat dosa. Penggunaan umum lain dari baris kode berbahaya itu adalah untuk menulis "kerangka kerja voodoo" (orm, container injeksi, ...). Banyak orang menjadi religius tentang kerangka kerja seperti itu (baik untuk dan melawan mereka) jadi saya akan menghindari mengundang perang api dengan mengatakan tidak lain dari sebagian besar programmer tidak harus pergi ke sana.


1

String dibuat di area permanen memori tumpukan JVM. Jadi ya, itu benar-benar abadi dan tidak dapat diubah setelah dibuat. Karena dalam JVM, ada tiga jenis memori tumpukan: 1. Generasi muda 2. Generasi tua 3. Generasi permanen.

Ketika objek apa pun dibuat, ia masuk ke area tumpukan generasi muda dan area PermGen dicadangkan untuk pengumpulan string.

Berikut ini detail lebih lanjut yang bisa Anda tuju dan dapatkan lebih banyak informasi dari: Bagaimana Pengumpulan Sampah bekerja di Jawa .


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.