A alocação e gerenciamento de memória Java são uma das principais tecnologias do Java. Anteriormente, introduzimos o conhecimento do gerenciamento de memória de Java, vazamento de memória e coleta de lixo Java. Hoje, mais uma vez nos aprofundaremos no núcleo Java e apresentaremos em detalhes o conhecimento do Java na alocação de memória. Geralmente, o Java envolverá as seguintes áreas ao alocar memória:
◆ Registro: não podemos controlá -lo no programa
◆ Pilha: armazena tipos básicos de dados e referências a objetos, mas o próprio objeto não é armazenado na pilha, mas é armazenado no heap (o objeto que sai de novo)
◆ Heap: armazenar dados gerados usando novo
◆ Domínio estático: membros estáticos armazenados em um objeto definido com estático
◆ Pool constante: armazenar constantes
◆ Armazenamento não-RAM: Espaço de armazenamento permanente, como disco rígido
Pilha na alocação de memória Java
Alguns tipos básicos de dados variáveis definidos nas variáveis de função e referência do objeto são todos alocados na memória da pilha da função.
Quando uma variável é definida em um bloco de código, o Java aloca espaço de memória para a variável na pilha. Quando a variável sair do escopo, o Java libera automaticamente o espaço de memória alocado para a variável e o espaço de memória pode ser usado separadamente imediatamente. O tamanho dos dados e o ciclo de vida na pilha são certos, e esses dados desaparecem quando nenhuma referência aponta para os dados.
Heap na alocação de memória Java
A memória da pilha é usada para armazenar objetos e matrizes criados pela New. A memória alocada na pilha é gerenciada pelo coletor automático de lixo da Java Virtual Machine.
Depois que uma matriz ou objeto é gerada na pilha, uma variável especial pode ser definida na pilha, para que o valor dessa variável na pilha seja igual ao primeiro endereço da matriz ou objeto na memória da pilha, e a variável na pilha se torna uma variável de referência para a matriz ou objeto. Uma variável de referência é equivalente a um nome dado a uma matriz ou objeto. Você pode usar as variáveis de referência na pilha no programa para acessar a matriz ou objeto na pilha. Uma variável de referência é equivalente a um nome dado a uma matriz ou objeto.
As variáveis de referência são variáveis comuns, que são atribuídas na pilha quando definidas. As variáveis de referência são liberadas após o desempenho do programa fora de seu escopo. A matriz e o objeto são alocados na pilha. Mesmo que o programa seja executado fora do bloco de código, onde as instruções que usam novas para gerar a matriz ou objeto estão localizadas, a memória ocupada pela matriz e o próprio objeto não será liberado. A matriz e o objeto só se tornam lixo quando não há variável de referência apontando para ela e não pode ser usada, mas ainda ocupa o espaço de memória. É coletado (liberado) pelo coletor de lixo em um momento incerto. Esta também é a razão pela qual Java ocupa mais memória.
De fato, variáveis no ponto de pilha para variáveis na memória da heap, que é o ponteiro em Java!
Pilha e pilha
O Heap de Java é uma área de dados de tempo de execução, da qual os objetos alocam espaço. Esses objetos são estabelecidos por meio de instruções como New, NewArray, Anewarray e MultianeWarray. Eles não exigem que o código do programa seja explicitamente liberado. A pilha é responsável pela coleta de lixo. A vantagem do heap é que ele pode alocar dinamicamente o tamanho da memória, e a vida útil não precisa ser contada ao compilador com antecedência, porque aloca dinamicamente a memória no tempo de execução. O coletor de lixo da Java coletará automaticamente os dados que não são mais usados. Mas a desvantagem é que, porque precisa alocar dinamicamente a memória em tempo de execução, a velocidade de acesso é mais lenta.
A vantagem da pilha é que a velocidade de acesso é mais rápida que a pilha, perdendo apenas para os registros, e os dados da pilha podem ser compartilhados. Mas a desvantagem é que o tamanho e a vida útil dos dados na pilha devem ser determinísticos e não ter flexibilidade. A pilha armazena principalmente alguns tipos básicos de dados variáveis (int, curto, longo, byte, flutuação, dupla, booleana, char) e alças de objetos (referências).
Um recurso especial muito importante da pilha é que os dados existentes na pilha podem ser compartilhados. Suponha que definimos ao mesmo tempo:
Código Java
int a = 3;
int b = 3;
O compilador primeiro processos int a = 3; Primeiro, ele criará uma referência na pilha com uma variável A e descobrirá se há um valor de 3 na pilha. Se não for encontrado, ele armazenará 3 e depois apontará a a 3. Então processará int b = 3; Depois de criar a variável de referência de B, porque já existe um valor de 3 na pilha, B é apontado diretamente para 3. Dessa maneira, A e B ambos apontam para 3 ao mesmo tempo.
Neste momento, se A = 4 estiver definido novamente; Em seguida, o compilador procurará novamente se há um valor 4 na pilha. Caso contrário, armazene 4 e ponto A a 4; Se já existir, aponte diretamente para este endereço. Portanto, a mudança no valor a não afetará o valor b.
Deve -se notar que esse compartilhamento de dados é diferente do compartilhamento de referências de dois objetos apontando para um objeto ao mesmo tempo, porque neste caso a modificação de A não afetará B, é feito pelo compilador, que é propício ao espaço para economizar. Uma variável de referência de objeto modifica o estado interno desse objeto e afetará outra variável de referência de objeto.
Código Java
1.INT I1 = 9;
2.INT i2 = 9;
3.Int i3 = 9;
4.Public estático final int1 = 9;
5.Public estático final int2 = 9;
6. Public estático final int3 = 9;
Para variáveis de membros e variáveis locais: as variáveis de membros são variáveis definidas dentro do método e da classe; As variáveis locais são variáveis definidas dentro do bloqueio de método ou declaração. As variáveis locais devem ser inicializadas.
Parâmetros formais são variáveis locais e os dados das variáveis locais existem na memória da pilha. As variáveis locais na memória da pilha desaparecem à medida que o método desaparece.
As variáveis de membros são armazenadas em objetos na pilha e são coletadas pelo coletor de lixo.
Como no código a seguir:
Código Java
classe BirthDate {private int Day; Mês privado int; Ano privado int; Public BirthDate (int d, int m, int y) {dia = d; mês = m; ano = y; } omita get, set método ……} public class Test {public static void main (string args []) {int date = 9; Teste de teste = novo teste (); test.change (data); Data de nascimento D1 = nova data de nascimento (7,7,1970); } public void alteração1 (int i) {i = 1234; }Para o código acima, a data é uma variável local, I, D, M, Y são parâmetros formais como variáveis locais e, dia, mês e ano, são variáveis de membros. Vamos analisar as alterações durante a execução do código:
1. O método principal começa a executar: int date = 9;
Data de variáveis locais, tipos básicos, referências e valores estão todos presentes na pilha.
2. Teste de teste = novo teste ();
O teste é uma referência de objeto, ele existe na pilha e o objeto (novo teste ()) existe na pilha.
3. Test.Change (data);
Eu é uma variável local e a referência e o valor estão presentes na pilha. Quando a alteração do método for executada, desaparecerei da pilha.
4. Data de nascimento D1 = nova data de nascimento (7,7,1970);
D1 é uma referência de objeto e existe na pilha. Os objetos (New BirthDate ()) existem na pilha, onde d, m, y são variáveis locais armazenadas na pilha, e seus tipos são os tipos de base, para que seus dados também sejam armazenados na pilha. O dia, mês, ano são variáveis de membros e são armazenados na heap (nova data de nascimento ()). Quando o construtor da data de nascimento é executado, D, M, Y desaparecerá da pilha.
5. Depois que o método principal for executado, a variável de data, o teste e a referência D1 desaparecerão da pilha e o novo teste (), o novo data de nascimento () aguardarão a coleta de lixo.
Piscina constante
Pools constantes referem -se a alguns dados que são determinados durante o período de compilação e são salvos no arquivo .class compilado.
Além de conter os valores constantes (final) de vários tipos básicos (como int, longa, etc.) e tipos de objetos (como string e matrizes) definidos no código, ele também contém algumas referências simbólicas na forma de texto, como:
◆ Os nomes totalmente qualificados de classes e interfaces;
◆ O nome e descritor do campo;
◆ Métodos, nomes e descritores.
Se o período de compilação tiver sido criado (definido diretamente em cotações duplas), ele será armazenado no pool constante e, se puder ser determinado pelo período de execução (do novo), será armazenado na pilha. Para strings com iguais, sempre existe apenas uma cópia no pool constante e várias cópias na pilha.
String é um dados de embalagem especial. Pode ser usado:
Código Java
String str = new String ("ABC"); String str = "ABC";Existem duas formas para criar. O primeiro é usar o novo () para criar um novo objeto, que será armazenado na pilha. Um novo objeto é criado toda vez que é chamado. O segundo tipo é primeiro criar uma variável STR para o objeto da classe String na pilha e depois usar referência simbólica para descobrir se existe "ABC" no pool constante de string. Caso contrário, armazene "ABC" no pool constante de cordas e deixe o STR apontar para "ABC". Se já houver "ABC", deixe o STR apontar diretamente para "ABC".
Ao comparar se os valores da classe são iguais, use o método iguals (); Ao testar se as referências das duas classes de wrapper apontam para o mesmo objeto, use == e use o exemplo abaixo para ilustrar a teoria acima.
Código Java
String str1 = "abc"; string str2 = "abc"; system.out.println (str1 == str2); //verdadeiro
Pode -se observar que o STR1 e o STR2 apontam para o mesmo objeto.
Código Java
String str1 = new String ("ABC"); String str2 = new String ("ABC"); System.out.println (str1 == str2); // falseO novo método é gerar objetos diferentes. Gerar um de cada vez.
Portanto, da segunda maneira, várias seqüências "ABC" são criadas e há apenas um objeto na memória. Este método de escrita é benéfico e salva o espaço da memória. Ao mesmo tempo, pode melhorar a velocidade de execução do programa até certo ponto, porque a JVM decidirá automaticamente se é necessário criar um novo objeto com base na situação real dos dados na pilha. Para o código de string str = new String ("ABC");, novos objetos são criados na pilha, independentemente de seus valores de sequência serem iguais ou não, seja necessário criar novos objetos, aumentando assim a carga do programa.
Por outro lado, observe: quando definimos uma classe usando um formato como String str = "ABC";, sempre tomamos como certo que criamos um objeto STR da classe String. Preocupe -se com a armadilha! O objeto pode não ter sido criado! E talvez apenas aponte para um objeto que foi criado anteriormente. Somente através do método novo () podemos garantir que um novo objeto seja criado sempre.
Vários exemplos de um problema constante de agrupamento
Exemplo 1:
Código Java
String S0 = "Kvill"; String S1 = "Kvill"; String S2 = "KV" + "III"; System.out.println (S0 == S1); System.out.println (S0 == S2); O resultado é: Truetrue
Análise: Antes de tudo, precisamos saber que o resultado é que o Java garantirá que uma constante de string tenha apenas uma cópia.
Como S0 e S1 no exemplo são constantes de sequência, elas são determinadas durante o período de compilação, portanto, S0 == S1 é verdadeiro; e "KV" e "III" também são constantes de cordas. Quando uma string é conectada por várias constantes de string, é definitivamente uma constante de string, portanto, o S2 também é analisado em uma constante de string durante o período de compilação, então o S2 também é uma referência a "Kvill" no pool constante. Então, obtemos S0 == S1 == S2;
Exemplo 2:
Exemplo:
Código Java
Análise: As strings criadas com new string () não são constantes e não podem ser determinadas durante o período de compilação; portanto, as strings criadas por new string () não são colocadas no pool constante, elas têm seu próprio espaço de endereço.
S0 também é uma aplicação de "Kvill" no pool constante. O S1 não pode ser determinado durante o período de compilação, por isso é uma referência ao novo objeto "Kvill" criado em tempo de execução. S2 não pode ser determinado durante o período de compilação porque possui a segunda metade da nova string ("III"), por isso é também uma aplicação do objeto recém -criado "Kvill"; Se você entender isso, saberá por que esse resultado é obtido.
Exemplo 3:
Código Java
String a = "a1"; string b = "a" + 1; system.out.println ((a == b)); // resultado = true string a = "true"; string b = "a" + "true"; system.out.println ((a == b)); // resultado = true string a = "a3.4"; string b = "a" + 3.4; system.out.println ((a == b)); // resultado = true
Análise: Para a conexão JVM de constantes de string, a JVM otimiza a conexão "+" da sequência constante ao valor conectado após o período de compilação do programa. Pegue "A" + 1 como exemplo. Após a otimização do compilador, ele já está A1 na classe. Durante o período de compilação, o valor da constante da string é determinado; portanto, o resultado final do programa acima é verdadeiro.
Exemplo 4:
Código Java
String a = "ab"; string bb = "b"; string b = "a" + bb; system.out.println ((a == b)); // resultado = false
Análise: Para referências de string na JVM, uma vez que existem referências de string na conexão " +" de seqüências de caracteres, o valor referenciado não pode ser determinado durante o período de compilação do programa, ou seja, "a" + BB não pode ser otimizado pelo compilador e apenas alocar dinamicamente e atribuir o novo endereço conectado ao período de execução do programa. Portanto, o resultado do programa acima é falso.
Exemplo 5:
Código Java
String a = "ab"; string final bb = "b"; string b = "a" + bb; system.out.println ((a == b)); // resultado = true
Análise: A única diferença entre [4] é que a corda BB é decorada com modificação final. Para variáveis finais finais, é analisado como uma cópia local do valor constante no tempo de compilação e armazenado em seu próprio pool constante ou incorporado em seu fluxo de bytecode. Portanto, neste momento, os efeitos de "A" + BB e "A" + "B" são os mesmos. Portanto, o resultado do programa acima é verdadeiro.
Exemplo 6:
Código Java
String a = "ab"; string final bb = getbb (); string b = "a" + bb; system.out.println ((a == b)); // resultado = string estática falsaPrivate getBb () {return "b"; }Análise: As referências da JVM para strings e seu valor não podem ser determinadas durante o período de compilação. Somente depois de ligar para o método durante o tempo de execução do programa, o valor de retorno do método e "A" está conectado dinamicamente e o endereço é atribuído a b. Portanto, o resultado do programa acima é falso.
Sobre String é imutável
Do exemplo acima, podemos descobrir:
String s = "a" + "b" + "c";
É equivalente a string s = "abc";
String a = "a";
String b = "b";
String c = "c";
String s = a + b + c;
Isso é diferente, o resultado final é igual a:
Código Java
Stringbuffer temp = new stringbuffer (); temp.append (a) .append (b) .append (c); string s = temp.toString ();
Nos resultados da análise acima, não é difícil inferir que a String usa o operador de conexão (+) para analisar o motivo da ineficiência, como este código:
Código Java
classe pública teste {public static void main (string args []) {string s = null; for (int i = 0; i <100; i ++) {s+= "a"; }}}Cada vez que + é feito, um objeto StringBuilder é gerado e depois o anexa e o joga fora. Na próxima vez que o loop chegar, um objeto StringBuilder for regenerado e, em seguida, anexar a sequência e o loop é concluído até que termine. Se usarmos diretamente o objeto StringBuilder para anexar, podemos economizar n - 1 tempo para criar e destruir o objeto. Portanto, para aplicativos que requerem concatenação de string em um loop, a operação do APEND é geralmente executada usando objetos StringBuffer ou StringBulider.
Devido à natureza imutável da classe String, há muito a dizer sobre isso. Contanto que você saiba que a instância da String não mudará quando for gerada, por exemplo: String str = "Kv"+"III"+""+"Ans"; Existem 4 constantes de corda, primeiro "kv" e "doente" geram "kvill" na memória e, em seguida, "kvill" e "" "geram" kvill "e" "e, finalmente, gerar" kvill ans "; e atribuir o endereço desse string a str, porque o string de string" gera muitas variáveis temporárias, que é o que é recomendado.
Uso final e entendimento em cordas
Código Java
Final StringBuffer A = new StringBuffer ("111"); Final StringBuffer B = new StringBuffer ("222"); a = b; // Esta frase não é compilada até que seja concluída. Final StringBuffer A = new StringBuffer ("111"); A.Append ("222"); /// Compile depois que terminarPode -se observar que o final é válido apenas para o "valor" referenciado (ou seja, endereço de memória). Força a referência a apontar apenas para o objeto que foi inicialmente apontado. Mudar seus apontamentos causará um erro de tempo de compilação. Quanto às mudanças no objeto em que aponta, Final é irresponsável.
Resumir
A pilha é usada para armazenar alguns dados variáveis locais do tipo de dados original e referências a objetos (string, matriz, objeto etc.), mas não armazena conteúdo de objeto
Os objetos criados usando a nova palavra -chave são armazenados na pilha.
Uma string é uma classe de invólucro especial e suas referências são armazenadas na pilha, e o conteúdo do objeto deve ser determinado de acordo com o método de criação (pool constante e heap). Alguns são criados no horário de compilação e armazenados no pool constante de string, enquanto outros são criados apenas em tempo de execução. Use a nova palavra -chave e armazenado na pilha.
O artigo acima fala brevemente sobre a diferença entre a alocação de memória Java+ e o local de armazenamento variável é 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.