Vous pouvez souvent voir des discussions sur l'allocation de mémoire des chaînes Java lors de l'exécution dans des sections principales sur Internet, telles que: String A = "123", String B = nouvelle chaîne ("123"), où ces deux formes de chaînes sont-elles stockées? En fait, la valeur littérale de la chaîne "123" dans ces deux formes n'est pas stockée sur la pile ni sur le tas de l'exécution. Ils sont stockés dans une certaine zone constante dans la zone de la méthode, et une seule copie est conservée en mémoire pour la même valeur littérale de chaîne. Nous l'analyserons avec des exemples ci-dessous.
1. L'opérateur == est utilisé dans deux cas où les comparaisons de référence de deux chaînes sont comparées:
classe publique StringTest {public static void main (String [] args) {// partie 1 String S1 = "I Love China"; String s2 = "J'adore la Chine"; System.out.println ("Résultat:" + S1 == S2); // Le résultat du programme est vrai // partie 2 String S3 = nouvelle chaîne ("I Love China"); String S4 = nouvelle chaîne ("J'adore la Chine"); System.out.println ("Résultat:" + S3 == S4); // Le résultat du programme est faux}}Nous savons que l'opérateur == en Java compare les valeurs des variables. La valeur de la variable correspondant au type de référence stocke l'adresse de l'objet de référence. Ici, la chaîne est le type de référence, et les valeurs des quatre variables ici stockent en fait les adresses de la chaîne. Le résultat de l'exécution de la partie2 est évident, car le nouvel opérateur entraînera la création de nouveaux objets de JVM dans le tas lors de l'exécution, et les adresses des deux objets différents sont différentes. Cependant, d'après le résultat d'exécution de la partie 1, on peut voir que S1 et S2 sont la même adresse indiquée. Alors, où les cordes sont-elles indiquées par les variables S1 et S2 stockées? Comment JVM gère-t-il les chaînes? De même, pour différents objets de chaîne dans le tas pointés par les variables S3 et S4, sauveront-ils une chaîne "j'aime la Chine" dans leur propre espace objet? Afin de comprendre comment JVM gère les chaînes, nous examinons d'abord les instructions Bytecode générées par le compilateur Java. Grâce à l'instruction Bytecode, nous analysons les opérations effectuées par JVM.
2. Voici quelques informations bytecode générées par le programme. Le rouge marque la pièce à laquelle nous devons prêter attention.
Pool constant: # 1 = classe # 2 // stringtest # 2 = utf8 stringtest # 3 = classe # 4 // java / lang / objet # 4 = utf8 java / lang / objet # 5 = utf8 <Init> # 6 = utf8 () v # 7 = utf8 Code # 8 = Methodref # 3. # 9 // java / lang / objet. # 5: # 6 // "<init>" :() v # 10 = utf8 lineNumberTable # 11 = utf8 localVariabEtable # 12 = utf8 this # 13 = utf8 lStringtest; # 14 = UTF8 Main # 15 = UTF8 ([Ljava / Lang / String;) V # 16 = String # 17 // J'adore la Chine Référence à l'adresse de la chaîne # 17 = UTF8 I Love China # 18 = FIELDREF # 19. # 21 // Java / Lang / System.out: ljava / io / printStream; # 19 = classe # 20 // Java / Lang / System # 20 = UTF8 Java / Lang / System # 21 = NameandType # 22: # 23 // Out: ljava / io / printStream; # 22 = UTF8 OUT # 23 = UTF8 LJAVA / IO / PRINTSTREAM; # 24 = classe # 25 // Java / Lang / StringBuilder # 25 = UTF8 Java / Lang / StringBuilder # 26 = String # 27 // Résultat: # 27 = UTF8 Résultat: # 28 = MethodRef # 24. # 29 // Java / Lang / StringBuilder. "<Init>" :( ljava / lang;) V # 29 = NAMANDY "<init>" :( ljava / lang / string;) v # 30 = utf8 (ljava / lang / string;) v # 31 = methodref # 24. # 32 // java / lang / stringBuilder.append: (z) ljava / lang / stringBuilder; # 32 = nameandtype # 33: # 34 // APPENDE: (z) ljava / lang / StringBuilder; # 33 = UTF8 APPEND # 34 = UTF8 (Z) Ljava / Lang / StringBuilder; # 35 = MethodRef # 24. # 36 // Java / Lang / StringBuilder.ToString: () Ljava / # 38 / # 38 / # 38 = namandtype toString :() ljava / lang / string; # 37 = utf8 toString # 38 = utf8 () ljava / lang / string; # 39 = méthodref # 40. # 42 // java / io / imprimer.println: (ljava / lang / string;) v # 40 = classe # 41 // java / io / io 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."<init>":(Ljava/lang/String;)V#47 = Utf8 args#48 = Utf8 [Ljava/lang/String;#49 = Utf8 s1#50 = Utf8 Ljava/lang/String;#51 = Utf8 s2#52 = Utf8 s3#53 = Utf8 s4#54 = Utf8 StackMaptable # 55 = classe # 48 // "[ljava / lang / string;" # 56 = utf8 sourcefile # 57 = utf8 stringtest.java ............ // L'instruction bytecode pour la méthode correspondante est expliquée et exécutée par le runtime jvm. public static void main (java.lang.string []); Descripteur: ([Ljava / Lang / String;) V INCLAPÉRIEURS: ACC_PUBLIC, CODE ACC_STATIQUE: Stack = 4, Locals = 5, Args_Size = 1 0: LDC # 16 // String I Love China, cette directive se réfère au symbole du haut de la pile constante. Cette instruction correspond à l'instruction suivante 2. String S1 = "I Love China" Instruction 2 dans le programme: Store_1 // Attribuez la référence de l'objet en haut de la pile à la variable locale 1. 3: LDC # 16 // String I Love China, l'instruction au même 0 points à une constante à la même référence de symbole. Cette instruction et l'instruction suivante 5 correspondent à la instruction S2 = "J'adore la Chine" dans le programme. 5: Store_2 // Attribuez des références d'objet aux variables locales en haut de la pile 2. 6: GetStatic # 18 // Field Java / Lang / System.out: ljava / io / printStream; 9: Nouveau # 24 // Classe Java / Lang / StringBuilder 12: DUP 13: LDC # 26 // Résultat de la chaîne: 15: InvokeSpecial # 28 // Méthode Java / Lang / StringBuilder. "<Init>" :( ljava / lang / String;) v 18: aload_1 19: ALOAD_2 20: IF_ACMPNE Comparez s'ils sont égaux ou non, accédez à la directive 27, exécutez, exécutez les instructions suivantes également 23: iconst_1 24: Goto 28 27: iconst_0 28: invokevirtual # 31 // méthode java / lang / stringBuilder.append: (z) ljava / lang / stringBuilder; 31: invokeVirtual # 35 // Méthode java / lang / stringbuilder.tostring :() ljava / lang / string; 34: Invokevirtual # 39 // Méthode java / io / printStream.println: (ljava / lang / string;) v 37: new # 44 // classe Java / Lang / String, Créer un objet, qui est situé au sommet de la piole constante # 44, voici l'objet de chaîne, et la référence d'objet est poussée vers le haut de la pile. 40: DUP // Copiez une copie de l'objet en haut de la pile et poussez-la en haut de la pile. 41: LDC # 16 // String J'adore la Chine, identique à 0, 3 instructions. 43: InvokeSpecial # 46 // Méthode Java / Lang / String. "<Init>" :( ljava / lang / string;) v 46: store_3 47: Nouveau # 44 // classe Java / Lang / String // Créer un objet et pousser l'objet en haut de la pile 50: DUP 51: LDC # 16 // String I Love China, poussez le symbole de la chaîne à la pile de la pile de la pile. 53: InvokeSpecial # 46 // Méthode Java / Lang / String. "<Init>" :( ljava / lang / string;) v, appelez la méthode d'initialisation de l'initialisation de l'objet en fonction de la référence d'objet correspondante en haut de la référence de la chaîne et de la chaîne, initialisez l'objet String 56: Store 4 // Attribuez la référence de l'objet à la variable 4. 58: GetStatic # 18 // java / lang / system.out: ljava / io / printStream; 61: Nouveau # 24 // Classe Java / Lang / StringBuilder 64: DUP 65: LDC # 26 // Résultat de la chaîne: 67: InvokeSpecial # 28 // Méthode Java / Lang / StringBuilder.APPEND: (z) Ljava / Lang / StringBuilder; 84: invokeVirtual # 35 // Méthode java / lang / stringbuilder.tostring :() ljava / lang / stringBuilder.append: (z) ljava / lang / stringBuilder; 84: invokeVirtual # 35 // Méthode java / lang / stringbuilder.tostring :() ljava / lang / stringBuilder; 87: invokevirtual # 39 // Méthode 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: 90Localvariableable: start Longueur Slot Name Signature91 0 arbores [Ljava / Lang / String; // Variable locale 088 1 S1 Ljava / Lang / String; // Variable locale 185 2 S2 Ljava / Lang / String; // Variable locale 244 3 S3 Ljava / Lang / String; // Variable locale 333 4 S4 Ljava / Lang / String; // Variable locale 4
La partie rouge du bytecode est liée à notre discussion. Grâce au bytecode généré, nous pouvons tirer les conclusions suivantes pour l'exemple de programme.
1). Lorsque le compilateur Java compile le programme en bytecode, la string constante "I Love China" rencontrée d'abord détermine s'il existe dans le pool constant de bytecode. S'il n'existe pas, il ne le créera pas. C'est-à-dire qu'une chaîne égale est réservée. Une seule copie peut être trouvée à travers des références symboliques, de sorte que les variables de chaîne S1 et S2 dans le programme pointent la même constante de chaîne dans le pool constant. Au moment de l'exécution, JVM stockera les constantes de chaîne dans le pool constant bytecode à l'emplacement de la zone de méthode communément appelée pool constant, et la chaîne est accessible par des index sous la forme d'un tableau de caractères. JVM pointe l'adresse de référence relative de la chaîne pointée par S1 et S2 à l'adresse mémoire réelle de la chaîne au moment de l'exécution.
2). Pour String S3 = Nouvelle String ("I Love China"), String S4 = New String ("I Love China"), à partir du bytecode, on peut voir qu'il appelle la nouvelle instruction. JVM créera deux objets différents lors de l'exécution, et S3 et S4 pointent vers différentes adresses d'objet. Par conséquent, le résultat de la comparaison S3 == S4 est faux.
Deuxièmement, pour l'initialisation des objets S3 et S4, il est vu à partir du bytecode que la méthode init de l'objet est appelée et que la référence "j'aime la Chine" dans le pool constant est passé. Alors, quelle est la création de l'objet String et l'initialisation fait? Nous pouvons vérifier le code source de la chaîne et le bytecode généré par l'objet String pour mieux comprendre si la chaîne est copiée à l'intérieur de l'objet ou la référence directement à l'adresse du pool constant correspondant à la chaîne est indiquée.
3. Partie du code source de l'objet String:
<Span style = "font-size: 14pt"> public final class String implémente java.io.serializable, comparable <string>, chardequence {/ ** La valeur est utilisée pour le stockage des caractères. * / Valeur de char finale privée []; / ** cache le code de hachage pour la chaîne * / private int hash; // par défaut à 0 String public () {this.value = new char [0]; } </span> <span style = "background-Color: #ffffff; font-size: 18pt"> public String (String Original) {this.value = original.Value; this.hash = original.hash; } </span>À partir du code source, nous voyons qu'il existe une valeur de char variable d'instance [] dans la classe String. Grâce à la méthode de construction, nous pouvons voir que l'objet n'effectue pas les opérations de copie lors de l'initialisation, mais affecte uniquement la référence d'adresse de l'objet de chaîne passée à la valeur de variable d'instance. À partir de cela, nous pouvons initialement conclure que même lorsqu'un objet String est créé à l'aide de New String ("ABC"), l'espace est alloué pour l'objet dans le tas de mémoire, mais aucune information sur "ABC" elle-même n'est stockée sur le tas, mais la référence à la chaîne "ABC" n'est initialisée dans sa variable d'instance à la chaîne "ABC". En fait, il s'agit également d'économiser de l'espace de stockage de la mémoire et d'améliorer les performances du programme.
4. Jetons un coup d'œil aux informations de bytecode de l'objet String:
public java.lang.string (); Descripteur: () V Flags: ACC_PUBLIC CODE: Stack = 2, Locals = 1, Args_Size = 1 0: Aload_0 1: InvokeSpecial # 1 // Méthode Java / Lang / Object. "<Init>" :() V 4: ALOAD_0 5: iconst_0 6: NewAray Char 8: Putfield # 2 // 138: 4 ligne 139: 11 public java.lang.string (java.lang.string); Descripteur: (Ljava / Lang / String;) V Flags: ACC_PUBLIC Code: Stack = 2, Locals = 2, args_size = 2 0: aload_0 // pousse la variable locale 0 en haut de la pile, une référence à son propre objet. 1: InvokeSpecial # 1 // Méthode java / lang / objet. "<Init>" :() v Fongez l'objet top pile pour se référer à la méthode d'initialisation au n ° 1 de l'objet. 4: Aload_0 // pousse la référence de son propre objet vers le haut de la pile. 5: Aload_1 // La référence de chaîne passée pousse en haut de la pile. 6: GetField # 2 // Valeur de champ: [c // apparaissez la référence de chaîne en haut de la pile et affectez-la à la variable d'instance au # 2, et stockez-la sur la pile. 9: PutField # 2 // Valeur de champ: [c // apparaît la référence de chaîne en haut de la pile et l'objet lui-même et affectez la référence de chaîne à la variable d'instance de l'objet lui-même. 12: Aload_0 13: Aload_1 14: Getfield # 3 // Hash de champ: I 17: Putfield # 3 // Hash de champ: I 20: Retour
Du point de vue de ByteCode, nous pouvons conclure que la nouvelle chaîne ("ABC") effectue des affectations de références de chaîne lors de la construction d'un nouvel objet, plutôt que de copier des chaînes. Ce qui précède est une analyse et un résumé de l'allocation de mémoire des chaînes du point de vue du code source et du code d'octets.
L'analyse et le résumé ci-dessus de l'allocation de mémoire Java String (recommandés) sont tout le contenu que je partage avec vous. J'espère que vous pourrez vous faire référence et j'espère que vous pourrez soutenir Wulin.com plus.