Este artigo explica principalmente seu princípio de funcionamento em detalhes, analisando a pilha, o heap e o pool constante de alocação de memória Java.
1. Protótipo de memória de máquina virtual Java
Registrar: Não temos controle sobre o programa. Pilha: armazena tipos básicos de dados e referências de objetos, mas o objeto em si não é armazenado na pilha, mas sim no heap: armazena os dados gerados com o novo domínio. : é armazenado no objeto. Conjunto de constantes de membro estático definido com estático: armazena constantes não RAM: espaço de armazenamento permanente, como disco rígido.
2. Piscina constante
O pool constante refere-se ao pool constante que é determinado em tempo de compilação e salvo na memória compilada. Alguns dados no arquivo de classe. Além dos valores constantes (finais) que contêm vários tipos básicos (como int, long, etc.) e tipos de objetos (como String e arrays) definidos no código, ele também contém algumas referências simbólicas em formato de texto , como:
1. Nomes totalmente qualificados de classes e interfaces;
2. Nome e descritor do campo;
3. Métodos, nomes e descritores.
A máquina virtual deve manter um pool constante para cada tipo carregado. O conjunto de constantes é um conjunto ordenado de constantes usadas por este tipo, incluindo constantes diretas (string, inteiro e constantes de ponto flutuante) e referências simbólicas a outros tipos, campos e métodos. Para constantes String, seus valores estão no conjunto de constantes. O conjunto de constantes na JVM existe na forma de uma tabela na memória. Para o tipo String, há uma tabela CONSTANT_String_info de comprimento fixo usada para armazenar valores de sequência literais. Nota: Esta tabela armazena apenas valores de sequência literais, não símbolos. . Dito isto, você deve ter uma compreensão clara do local de armazenamento dos valores de string no pool constante. Quando o programa for executado, o pool constante será armazenado na Área de Métodos em vez do heap.
3. Pilha na alocação de memória Java
A unidade básica da pilha é o quadro (ou quadro de pilha): sempre que um thread Java é executado, a máquina virtual Java aloca uma pilha Java para o thread. Quando o thread executa um determinado método Java, ele envia um quadro para a pilha Java. Esse quadro é usado para armazenar parâmetros, variáveis locais, operandos, resultados de operações intermediárias, etc. Quando este método concluir a execução, o quadro será retirado da pilha. Todos os dados na pilha Java são privados e nenhum outro thread pode acessar os dados da pilha do thread. Alguns tipos básicos de dados variáveis e variáveis de referência de objeto definidos na função são alocados na memória da pilha da função. Quando uma variável é definida em um bloco de código, Java aloca espaço de memória para a variável na pilha. Quando a variável sai do escopo, Java libera automaticamente o espaço de memória alocado para a variável, e o espaço de memória pode ser usado imediatamente. ser usado para outros fins.
4. Heap na alocação de memória Java
O heap na máquina virtual Java é usado para armazenar objetos e arrays criados por novos. A memória alocada no heap é gerenciada pelo mecanismo automático de coleta de lixo da máquina virtual Java. Simplificando, em comparação com a pilha, o heap é usado principalmente para armazenar objetos Java, e a pilha é usada principalmente para armazenar referências de objetos... Depois que uma matriz ou objeto é gerado no heap, uma variável especial também pode ser definido na pilha, de modo que O valor desta variável na pilha seja igual ao primeiro endereço do array ou objeto na memória heap. Esta variável na pilha se torna a variável de referência do array ou objeto. Uma variável de referência é equivalente a dar um nome a um array ou objeto. Você pode então usar a variável de referência na pilha para acessar o array ou objeto no heap do programa. Uma variável de referência equivale a dar um nome a um array ou objeto.
Variáveis de referência são variáveis comuns que são alocadas na pilha quando definidas. As variáveis de referência são liberadas depois que o programa é executado fora de seu escopo. Os próprios arrays e objetos são alocados no heap Mesmo que o programa seja executado fora do bloco de código onde está localizada a instrução que usa new para gerar o array ou objeto, a memória ocupada pelo array e pelo próprio objeto não será liberada. objetos não possuem variáveis de referência apontando para eles, torna-se lixo e não pode mais ser utilizado, mas ainda ocupa espaço de memória e será coletado (liberado) pelo coletor de lixo em tempo indeterminado posteriormente. Esta também é a razão pela qual Java ocupa mais memória. Na verdade, variáveis na pilha apontam para variáveis na memória heap. Este é um ponteiro em Java!
O heap de Java é uma área de dados de tempo de execução a partir da qual os objetos de classe alocam espaço. Esses objetos são criados por meio de instruções como new, newaray, anewarray e multianewarray e não exigem que o código do programa seja explicitamente liberado. Responsável, a vantagem do heap é que ele pode alocar dinamicamente o tamanho da memória, e o tempo de vida não precisa ser informado ao compilador com antecedência, porque ele aloca memória dinamicamente em tempo de execução, e o coletor de lixo do Java coletará automaticamente aqueles que não são mais usados dados Mas a desvantagem é que devido à necessidade de alocar memória dinamicamente em tempo de execução, a velocidade de acesso é lenta.
A vantagem da pilha é que a velocidade de acesso é mais rápida que a do heap, perdendo apenas para o registrador, e os dados da pilha podem ser compartilhados. Mas a desvantagem é que o tamanho e a vida útil dos dados armazenados na pilha devem ser determinados e há falta de flexibilidade. A pilha armazena principalmente alguns tipos básicos de dados variáveis (int, short, long, byte, float, double, boolean, char) e manipuladores de objetos (referências).
Uma característica especial muito importante da pilha é que os dados armazenados na pilha podem ser compartilhados. Suponha que também definimos:
int a=3; int b=3; O compilador primeiro processa int a = 3; primeiro ele cria uma referência à variável a na pilha e depois verifica se há um valor 3 na pilha. ele definirá 3 Armazene-o e aponte a para 3. Em seguida, processe int b = 3 após criar a variável de referência de b, porque já existe um valor de 3 na pilha, b será apontado diretamente para 3; Desta forma, a e b aparecem ao mesmo tempo, ambos apontam para o caso de 3.
Neste momento, se a=4 for definido novamente, o compilador irá pesquisar se existe um valor 4 na pilha. Caso contrário, ele armazenará 4 e apontará para 4; apontará diretamente para este endereço. Portanto, alterações no valor de a não afetarão o valor de b.
Deve-se notar que este tipo de compartilhamento de dados é diferente do compartilhamento de referências de dois objetos apontando para um objeto ao mesmo tempo, pois neste caso a modificação de a não afetará b, ela é completada pelo compilador, que é benéfico para economizar espaço. Se uma variável de referência de objeto modificar o estado interno do objeto, ela afetará outra variável de referência de objeto.