Muitas vezes, você pode ver discussões sobre a alocação de memória de strings de java ao executar nas principais seções da Internet, como: string a = "123", string b = new string ("123"), onde estão armazenadas essas duas formas? De fato, o valor literal da string "123" nessas duas formas não é armazenado na pilha nem na pilha em tempo de execução. Eles são armazenados em uma certa área constante na área do método, e apenas uma cópia é retida na memória pelo mesmo valor literal de string. Vamos analisá -lo com exemplos abaixo.
1. O operador == é usado em dois casos em que duas comparações de referência de string são comparadas:
classe pública stringtest {public static void main (string [] args) {// parte 1 string s1 = "eu amo a China"; String s2 = "eu amo a China"; System.out.println ("Resultado:" + S1 == S2); // O resultado da execução do programa é verdadeiro // Parte 2 String S3 = new String ("I Love China"); String s4 = new String ("Eu amo a China"); System.out.println ("Resultado:" + S3 == S4); // O resultado da execução do programa é false}}Sabemos que o operador == em Java compara os valores das variáveis. O valor da variável correspondente ao tipo de referência armazena o endereço do objeto de referência. Aqui a string é o tipo de referência e os valores das quatro variáveis aqui armazenam os endereços da string. O resultado da execução para a Part2 é óbvio, porque o novo operador fará com que a JVM crie novos objetos na pilha em tempo de execução, e os endereços dos dois objetos diferentes são diferentes. No entanto, a partir do resultado da execução da Part1, pode -se ver que S1 e S2 são o mesmo endereço apontado. Então, onde as cordas são apontadas pelas variáveis S1 e S2 armazenadas? Como a JVM lida com as cordas? Da mesma forma, para diferentes objetos de string na pilha apontados pelas variáveis S3 e S4, eles salvarão uma corda "Eu amo a China" em seu próprio espaço de objeto? Para entender como a JVM lida com strings, primeiro analisamos as instruções de bytecode geradas pelo compilador Java. Através da instrução ByteCode, analisamos quais operações serão executadas pela JVM.
2. A seguir, são apresentadas algumas informações de bytecode geradas pelo programa. O vermelho marca a parte em que precisamos prestar atenção.
Constante Pool: #1 = Classe #2 // StringTest #2 = Utf8 StringTest #3 = Classe #4 // java/lang/objeto #4 = utf8 java/lang/objeto #5 = utf8 <iird> #6 = utf8 () v #7 = utf8 #8 = Methodref # # #9 // JAVA Nameandtype #5: #6 // "<iit>" :() v #10 = utf8 lineNumberTable #11 = utf8 localVariaBLETABLE #12 = utf8 this #13 = utf8 lStringtest; #14 = utf8 main #15 = utf8 ([ljava/lang/string;) v #16 = string #17 // eu amo a referência da China ao endereço da string #17 = utf8 eu amo a China #18 = fieldref #19. #21 // java/lang/system.out: ljava/io/printstream; #19 = classe #20 // java/lang/sistema #20 = utf8 java/lang/sistema #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 // Resultado: #27 = utf8 Resultado: #28 = MethodRef #24. #29 // java/lang/stringilder. "<ingit>" :( ljava/lang/string;) v#30 = utf8 (ljava/lang/string;) v#31 = MethodRef#24.#32 // java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder;#32 = nameanDtype. Anexar: (z) ljava/lang/stringbuilder;#33 = utf8 append#34 = utf8 (z) ljava/lang/stringbuilder;#35 = methodref#24.#36 // java/lang/stringbuilder.toString :() ljava/lang/string; tostring :() ljava/lang/string;#37 = utf8 tostring#38 = utf8 () ljava/lang/string;#39 = MethodRef#40.#42 // java/io/printStream.printn: (ljava/libr/string;) v#40 java/io/printStream#42 = nameandtype#43:#30 // println: (ljava/lang/string;) v#43 = utf8 println#44 = classe#45 // java/lang/string#45 = utf8 java/libr/string#46 java/lang/string. StackMaptable#55 = Classe#48 // "[ljava/lang/string;"#56 = utf8 Sourcefile#57 = utf8 stringtest.java ............ // A instrução ByteCode para o método correspondente é explicada e executada pelo tempo de execução da JVM. public static void main (java.lang.string []); Descritor: ([ljava/lang/string;) v sinalizadores: acc_public, acc_static Code: Stack = 4, habitantes locais = 5, args_size = 1 0: ldc #16 // string eu amo a porcelana, esta diretiva refere -se ao símbolo da #16 da constante piscina e aqui empurra a string "Illous" Symin " Esta instrução corresponde à seguinte instrução 2. String s1 = "eu amo a China" Declaração 2 No programa: store_1 // atribui a referência do objeto na parte superior da pilha à variável local 1. 3: ldc #16 // string eu amo a China, a instrução nos mesmos pontos para uma constante na mesma referência de símbolo. Esta instrução e a seguinte instrução 5 correspondem à declaração da String S2 = "I Love China" no programa. 5: store_2 // atribui referências de objeto a variáveis locais na parte superior da pilha 2. 6: getstatic #18 // campo java/lang/system.out: ljava/io/printStream; 9: Novo #24 // Classe Java/Lang/StringBuilder 12: DUP 13: LDC #26 // String Resultado: 15: Invokespial #28 // Método java/lang/stringbuilder. "<ingem>" :( ljava/lang/string;) v 18: aload_1 19: aload_2 20: Compare se são iguais ou não, vá à Diretiva 27, execute, execute a próxima instrução igualmente 23: iconst_1 24: goto 28 27: iconst_0 28: InvokeVirtual #31 // Método java/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 31: InvokeVirtual #35 // Método java/lang/stringbuilder.toString :() ljava/lang/string; 34: InvokeVirtual #39 // Método java/io/printStream.println: (ljava/lang/string;) v 37: novo #44 // classe java/lang/string, crie um objeto, que está localizado na referência do pool constante, aqui está o objeto e o objeto. 40: dup // copie uma cópia do objeto na parte superior da pilha e empurre -a para a parte superior da pilha. 41: LDC #16 // String Eu amo a China, o mesmo que 0, 3 instruções. 43: Invokespial #46 // Método java/lang/string. 53: Invokespial #46 // Método java/lang/string. java/lang/system.out: ljava/io/printStream; 61: Novo #24 // Classe Java/Lang/Stringbuilder 64: DUP 65: LDC #26 // String Resultado: 67: Invokespial #28 // Método Java/Lang/Stringbuilder.append: (Z) ljava/lang/stringbuilder; 84: InvokeVirtual #35 // Método java/lang/stringbuilder.toString :() ljava/lang/stringbuilder.append: (z) ljava/lang/stringbuilder; 84: InvokeVirtual #35 // Método java/lang/stringbuilder.toString :() ljava/lang/stringbuilder; 87: InvokeVirtual #39 // Método java/io/printStream.println: (ljava/lang/string;) v 90: retornar ......... linenumbertable: linha 7: 0 linha 8: 3lina 9: 6 line 11: 37 line 12: 47 line 13: 58 line 14: 90localVariAbletS [Ljava/lang/string; // variável local 088 1 s1 ljava/lang/string; // variável local 185 2 s2 ljava/lang/string; // variável local 244 3 s3 ljava/lang/string; // variável local 333 4 s4 ljava/lang/string; // variável local 4
A parte vermelha do bytecode está relacionada à nossa discussão. Através do bytecode gerado, podemos tirar as seguintes conclusões para o programa de exemplo.
1). Quando o compilador Java compila o programa em bytecode, a string constante "I Love China" encontrada primeiro determina se ele existe no pool constante de bytecode. Se não existir, não o criará. Isto é, uma sequência igual é reservada. Apenas uma cópia pode ser encontrada através de referências simbólicas, de modo que as variáveis de string S1 e S2 no programa apontam para a mesma constante de string no pool constante. No tempo de execução, a JVM armazenará constantes de string no pool constante de bytecode na localização da área de método comumente chamado de pool constante, e a string é acessada através de índices na forma de uma matriz de caracteres. JVM aponta o endereço de referência relativo da string apontado por S1 e S2 para o endereço de memória real da string no tempo de execução.
2). Para String S3 = new String ("I Love China"), String S4 = new String ("I Love China"), do bytecode, pode -se ver que chama a nova instrução. A JVM criará dois objetos diferentes em tempo de execução, e S3 e S4 apontam para diferentes endereços de objetos. Portanto, o resultado da comparação S3 == S4 é falso.
Em segundo lugar, para a inicialização dos objetos S3 e S4, é visto no bytecode que o método init do objeto é chamado e a referência "eu amo a China" no pool constante é passada. Então, qual é a criação do objeto de string e a inicialização? Podemos verificar o código -fonte da string e o bytecode gerado pelo objeto String para entender melhor se a string é copiada dentro do objeto ou a referência diretamente ao endereço do pool constante correspondente à string é apontado.
3. Parte do código -fonte do objeto String:
<Span style = "font-size: 14pt"> a classe final pública String implementa java.io.serializable, comparável <string>, Charsequence { /** O valor é usado para armazenamento de caracteres. */ Valor de char final privado []; / ** cache o código de hash para a string*/ private int hash; // padrão para 0 public string () {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>A partir do código -fonte, vemos que existe uma variável de instância Valor de char [] na classe String. Através do método de construção, podemos ver que o objeto não executa operações de cópia ao inicializar, mas atribui apenas a referência de endereço do objeto String aprovado ao valor da variável da instância. A partir disso, podemos concluir inicialmente que, mesmo quando um objeto String é criado usando a nova string ("ABC"), o espaço é alocado para o objeto na pilha de memória, mas nenhuma informação sobre "ABC" em si é armazenada na pilha, mas a referência à sequência "ABC" é inicializada dentro de sua variável de instância para a sequência "ABC". De fato, isso também é para salvar o espaço de armazenamento de memória e melhorar o desempenho do programa.
4. Vamos dar uma olhada nas informações de bytecode do objeto String:
public java.lang.string (); Descritor: () v Flags: Acc_public Código: Stack = 2, habitantes locais = 1, args_size = 1 0: aload_0 1: InvokesPecial #1 // Método Java/Lang/Object. "<ing init>" :() v 4: aload_0 5: iconst_0 6: NewraRay Char 8: #): 4: Aload_0 5: iconst_0 6: NewraRay Char 8: Linha 138: 4 Linha 139: 11 Java Public Java.Lang.String (java.lang.string); Descritor: (ljava/lang/string;) v sinalizadores: Acc_public Code: Stack = 2, habitantes locais = 2, args_size = 2 0: aload_0 // empurre a variável local 0 para a parte superior da pilha, uma referência ao seu próprio objeto. 1: InvokesPpecial #1 // Método Java/Lang/Object. "<Inir>" :() V Encontre o objeto Top Stack para consultar o método de inicialização no número 1 do objeto. 4: aload_0 // empurre a referência de seu próprio objeto para a parte superior da pilha. 5: aload_1 // a referência de string passada empurre para a parte superior da pilha. 6: Getfield #2 // Valor do campo: [c // Popa a referência da string na parte superior da pilha e atribua -a à variável de instância no #2 e armazene -a na pilha. 9: Putfield #2 // Valor do campo: [c // coloque a referência da string na parte superior da pilha e no próprio objeto e atribua a referência da string à variável de instância do próprio objeto. 12: aload_0 13: aload_1 14: getfield #3 // hash de campo: i 17: putfield #3 // hash de campo: i 20: retornar
Do ponto de vista do bytecode, podemos concluir que a nova string ("ABC") executa atribuições de referências de string ao construir um novo objeto, em vez de copiar strings. O exposto acima é uma análise e resumo da alocação de memória de seqüências de caracteres da perspectiva do código -fonte e do código de byte.
A análise e o resumo acima da alocação de memória de string java (recomendada) é todo o conteúdo que compartilho com você. Espero que você possa lhe dar uma referência e espero que você possa apoiar mais o wulin.com.