Anda sering dapat melihat diskusi tentang alokasi memori string java saat berjalan di bagian utama di internet, seperti: string a = "123", string b = string baru ("123"), di mana dua bentuk string ini disimpan? Faktanya, nilai literal dari string "123" dalam dua bentuk ini tidak disimpan di tumpukan atau di tumpukan saat runtime. Mereka disimpan di area konstan tertentu di area metode, dan hanya satu salinan yang disimpan dalam memori untuk nilai literal string yang sama. Kami akan menganalisisnya dengan contoh di bawah ini.
1. Operator == digunakan dalam dua kasus di mana dua perbandingan referensi string dibandingkan:
kelas publik stringtest {public static void main (string [] args) {// bagian 1 string s1 = "I love china"; String S2 = "I Love China"; System.out.println ("Hasil:" + S1 == S2); // Hasil menjalankan program benar // Bagian 2 string S3 = string baru ("I Love China"); String s4 = string baru ("I Love China"); System.out.println ("Hasil:" + S3 == S4); // Hasil menjalankan program false}}Kita tahu bahwa operator == di Java membandingkan nilai variabel. Nilai variabel yang sesuai dengan jenis referensi menyimpan alamat objek referensi. Di sini string adalah jenis referensi, dan nilai -nilai dari empat variabel di sini sebenarnya menyimpan alamat string. Hasil eksekusi untuk part2 sudah jelas, karena operator baru akan menyebabkan JVM membuat objek baru di tumpukan saat runtime, dan alamat dua objek yang berbeda berbeda. Namun, dari hasil eksekusi part1, dapat dilihat bahwa S1 dan S2 adalah alamat yang sama. Jadi di mana string ditunjuk oleh variabel S1 dan S2 disimpan? Bagaimana JVM menangani string? Demikian pula, untuk objek string yang berbeda dalam tumpukan yang ditunjukkan oleh variabel S3 dan S4, akankah mereka menyimpan string "I Love China" di ruang objek mereka sendiri? Untuk memahami bagaimana JVM menangani string, pertama -tama kita melihat instruksi bytecode yang dihasilkan oleh kompiler Java. Melalui instruksi bytecode, kami menganalisis operasi apa yang akan dilakukan oleh JVM.
2. Berikut ini adalah beberapa informasi bytecode yang dihasilkan oleh program. Merah menandai bagian yang perlu kita perhatikan.
Pool konstan: #1 = Kelas #2 // StringTest #2 = UTF8 StringTest #3 = Kelas #4 // Java/Lang/Objek #4 = UTF8 Java/Lang/Object #5 = UTF8 <inin> #6 = UTF8 () V #7 = Kode UTF8. #5: #6 // "<init>" :() V #10 = UTF8 LinenumberTable #11 = UTF8 LocalVariableTable #12 = UTF8 Ini #13 = UTF8 LStringTest; #14 = UTF8 Main #15 = UTF8 ([Ljava/Lang/String;) V #16 = String #17 // Saya suka referensi China ke Alamat String #17 = UTF8 I Love China #18 = Fieldref #19. #21 // Java/Lang/System.out: ljava/io/printStream; #19 = kelas #20 // java/lang/sistem #20 = utf8 java/lang/sistem #21 = nameandtype #22: #23 // out: ljava/io/printStream; #22 = UTF8 OUT #23 = UTF8 Ljava/IO/printStream; #24 = kelas #25 // java/lang/stringbuilder #25 = utf8 java/lang/stringbuilder #26 = String #27 // Hasil: #27 = UTF8 Hasil: #28 = MethodRef #24. #29 // Java/Lang/StringBuilder. "<init>": #29 // Java/Lang/StringBuilder. "<init>": ljava/lang/lang/stringBuilder. "<Inin>" :( Ljava/lang/lang/lang/stringbuilder. "<InTIT>" :( LJAVA/Lang/Lang/StringBuilder. " // "<init>" :( ljava/lang/string;) v#30 = utf8 (ljava/lang/string;) v#31 = MethodRef#24.#32 // java/lang/stringbuilder.Append: (z) ljava/lang/stringbuilder;#32 = neMee. 32 = NameED; NameED#34:#32 = NAMEEAND#34 =#32 = NAMEEAND#32 =#32 = NAMEAND#32EAND; Tambahkan: (z) ljava/lang/stringbuilder;#33 = utf8 append#34 = utf8 (z) ljava/lang/stringbuilder;#35 = MethodRef#24.#36 // java/lang/stringbuilder.toString: ljava/lang/lang/lang; naM; neAnd.tostring# tostring :() ljava/lang/string;#37 = utf8 tostring#38 = utf8 () ljava/lang/string;#39 = MethodRef#40.#42 // java/io/printStream.println: (ljava/lang/string;) v#40 = cladstream. java/io/PrintStream#42 = NameAndType #43:#30 // println:(Ljava/lang/String;)V#43 = Utf8 println#44 = Class #45 // java/lang/String#45 = Utf8 java/lang/String#46 = Methodref #44.#29 // java/lang/string. "<inin>" :( ljava/lang/string;) v#47 = utf8 args#48 = utf8 [ljava/lang/string;#49 = utf8 S1#50 = UTF8 Ljava/Lang/String;#51 = UTF8 S2#52 = StackMaptable#55 = Kelas#48 // "[ljava/lang/string;"#56 = UTF8 SourceFile#57 = UTF8 StringTest.java ............ // Instruksi bytecode untuk metode yang sesuai dijelaskan dan dieksekusi oleh runtime JVM. public static void main (java.lang.string []); Deskriptor: ([ljava/lang/string;) v Bendera: acc_public, Acc_static Code: stack = 4, penduduk setempat = 5, args_size = 1 0: ldc #16 // string I Love China, arahan ini mengacu pada simbol pada #16 dari kumpulan konstan, dan di sini mendorong string "ilove" ilove "simbol TOP TOP. Instruksi ini sesuai dengan instruksi berikut 2. String S1 = "I Love China" Pernyataan 2 Dalam program: Store_1 // Tetapkan referensi objek di bagian atas tumpukan ke variabel lokal 1. 3: LDC #16 // String I Love China, instruksi pada 0 poin yang sama ke konstanta pada referensi simbol yang sama. Instruksi ini dan instruksi berikut 5 sesuai dengan string S2 = "I Love China" dalam program. 5: Store_2 // Tetapkan referensi objek ke variabel lokal di bagian atas tumpukan 2. 6: getStatic #18 // bidang java/lang/system.out: ljava/io/printStream; 9: new #24 // class java/lang/StringBuilder 12: dup 13: ldc #26 // String result: 15: invokespecial #28 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 18: aload_1 19: aload_2 20: if_acmpne 27 //Pop up the two object references on the top of the stack to Bandingkan apakah mereka sama atau tidak, buka directive 27, jalankan, jalankan instruksi berikutnya sama -sama 23: ICONST_1 24: GOTO 28 27: ICONST_0 28: Invokevirtual #31 // Metode Java/Lang/StringBuilder.Append: (Z) Ljava/Lang/StringBuilder; 31: Invokevirtual #35 // Metode Java/Lang/StringBuilder.tostring :() ljava/lang/string; 34: Invokevirtual #39 // Metode java/io/printStream.println: (ljava/lang/string;) v 37: baru #44 // kelas java/lang/string, buat objek, yang terletak di referensi kumpulan konstan #44, berikut adalah objek string, dan referensi objek adalah ke atas. 40: DUP // Salin salinan objek di bagian atas tumpukan dan dorong ke atas tumpukan. 41: LDC #16 // String I Love China, sama dengan 0, 3 instruksi. 43: invokespecial #46 // metode java/lang/string. "<inin>" :( ljava/lang/string;) v 46: store_3 47: baru #44 // kelas java/lang/string // membuat objek dan mendorong objek ke atas stack 50: dup 51: ldc #16 //. 53: Invokespecial #46 // Metode java/lang/string. "<inin>" :( ljava/lang/string;) v, panggil metode inisialisasi init objek sesuai dengan referensi objek yang sesuai di bagian atas tumpukan dan string, inisialisasi Objek String 56: Store 4 // Tetapkan referensi objek ke variabel 4. java/lang/system.out: ljava/io/printstream; 61: Baru #24 // Kelas Java/Lang/StringBuilder 64: Dup 65: LDC #26 // Hasil String: 67: Invokespecial #28 // Metode Java/Lang/StringBuilder.Append: (Z) Ljava/Lang/StringBuilder; 84: Invokevirtual #35 // Metode Java/Lang/StringBuilder.tostring :() ljava/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 84: Invokevirtual #35 // Metode Java/Lang/StringBuilder.tostring :() ljava/lang/stringBuilder; 87: invokevirtual #39 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 90: return.........LineNumberTable:line 7: 0line 8: 3line 9: 6line 11: 37line 12: 47line 13: 58line 14: 90LocalVariableTable:Start Length Slot Name Signature91 0 args [Ljava/lang/string; // variabel lokal 088 1 s1 ljava/lang/string; // variabel lokal 185 2 S2 ljava/lang/string; // variabel lokal 244 3 s3 ljava/lang/string; // variabel lokal 333 4 s4 ljava/lang/string; // variabel lokal 4
Bagian merah dari bytecode terkait dengan diskusi kami. Melalui bytecode yang dihasilkan, kita dapat menarik kesimpulan berikut untuk program contoh.
1). Ketika kompiler Java mengkompilasi program menjadi bytecode, string konstanta "I Love China" yang ditemui terlebih dahulu menentukan apakah ada di kumpulan konstanta bytecode. Jika tidak ada, itu tidak akan membuatnya. Artinya, string yang sama, hanya satu salinan yang dapat disimpan. Ini dapat ditemukan melalui referensi simbolik, sehingga variabel string S1 dan S2 dalam program menunjuk ke konstanta string yang sama di kumpulan konstan. Pada saat runtime, JVM akan menyimpan konstanta string di kumpulan konstanta bytecode di lokasi area metode yang biasa disebut kumpulan konstan, dan string diakses melalui indeks dalam bentuk array karakter. JVM menunjukkan alamat referensi relatif dari string yang ditunjukkan oleh S1 dan S2 ke alamat memori aktual dari string saat runtime.
2). Untuk String S3 = String baru ("I Love China"), String S4 = String baru ("I Love China"), dari bytecode, dapat dilihat bahwa ia menyebut instruksi baru. JVM akan membuat dua objek berbeda saat runtime, dan titik S3 dan S4 ke alamat objek yang berbeda. Oleh karena itu, hasil perbandingan S3 == S4 salah.
Kedua, untuk inisialisasi objek S3 dan S4, dilihat dari bytecode bahwa metode init objek disebut dan referensi "I Love China" di kolam konstan dilewatkan. Jadi apa pembuatan objek string dan inisialisasi? Kita dapat memeriksa kode sumber string dan bytecode yang dihasilkan oleh objek string untuk lebih memahami apakah string disalin di dalam objek atau referensi langsung ke alamat kumpulan konstan yang sesuai dengan string ditunjukkan.
3. Bagian dari kode sumber objek string:
<Span style = "font-size: 14pt"> Public Final Class String mengimplementasikan java.io.serializable, sebanding <string>, charsequence { /** nilainya digunakan untuk penyimpanan karakter. */ nilai arang akhir pribadi []; / ** cache kode hash untuk string*/ private int hash; // default ke 0 public string () {this.value = new char [0]; } </span> <span style = "latar belakang-warna: #ffffff; font-size: 18pt"> public string (string asli) {this.value = original.value; this.hash = original.hash; } </span>Dari kode sumber, kami melihat bahwa ada nilai variabel instance variabel [] di kelas string. Melalui metode konstruksi, kita dapat melihat bahwa objek tidak melakukan operasi penyalinan saat menginisialisasi, tetapi hanya menetapkan referensi alamat dari objek string yang dilewati ke nilai variabel instance. Dari sini kita awalnya dapat menyimpulkan bahwa bahkan ketika objek string dibuat menggunakan string baru ("ABC"), ruang dialokasikan untuk objek dalam tumpukan memori, tetapi tidak ada informasi tentang "ABC" itu sendiri disimpan pada tumpukan, tetapi referensi ke string "ABC" diinisialisasi dalam variabel instance ke string "ABC". Bahkan, ini juga untuk menghemat ruang penyimpanan memori dan meningkatkan kinerja program.
4. Mari kita lihat informasi bytecode dari objek string:
publik java.lang.string (); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: iconst_0 6: newarray char 8: putfield #2 // Field value:[C 11: return LineNumberTable: line 137: 0 line 138: 4 baris 139: 11 java.lang Public.string (java.lang.string); Deskriptor: (ljava/lang/string;) v Bendera: ACC_PUBLIC Kode: stack = 2, penduduk setempat = 2, args_size = 2 0: aload_0 // Dorong variabel lokal 0 ke bagian atas tumpukan, referensi ke objeknya sendiri. 1: Invokespecial #1 // Metode Java/Lang/Object. "<inin>" :() v Puncak Objek Teratas Stack untuk merujuk ke metode inisialisasi di #1 dari objek. 4: Aload_0 // Dorong referensi objeknya sendiri ke bagian atas tumpukan. 5: Aload_1 // Dorong referensi string yang dilewati ke bagian atas tumpukan. 6: Getfield #2 // Nilai Bidang: [c // Pop referensi string di bagian atas tumpukan dan tetapkan ke variabel instance di #2, dan simpan di tumpukan. 9: Putfield #2 // Nilai Bidang: [c // Pop referensi string di bagian atas tumpukan dan objek itu sendiri dan tetapkan referensi string ke variabel instance objek itu sendiri. 12: Aload_0 13: Aload_1 14: Getfield #3 // Field Hash: I 17: Putfield #3 // Field Hash: I 20: Return
Dari perspektif bytecode, kita dapat menyimpulkan bahwa string baru ("ABC") melakukan penugasan referensi string saat membangun objek baru, daripada menyalin string. Di atas adalah analisis dan ringkasan alokasi memori string dari perspektif kode sumber dan kode byte.
Analisis dan ringkasan alokasi memori string Java (disarankan) adalah semua konten yang saya bagikan dengan Anda. Saya harap Anda dapat memberi Anda referensi dan saya harap Anda dapat mendukung wulin.com lebih lanjut.