Introdução à Máquina Virtual Java (JVM)

7a34bba3e436432f98a97feac69e20dc.jpgO que é JVM

 

JVM é a abreviação de Java Virtual Machine. É uma especificação baseada em um dispositivo de computação que é uma máquina virtual, um computador imaginário.

 

A JVM blinda as informações da plataforma específica do sistema operacional (obviamente, é como se tivéssemos aberto uma máquina virtual no computador). Claro que quando a JVM executa o bytecode, na verdade ele precisa ser interpretado nas instruções de máquina do plataforma operacional específica.

 

Por meio da JVM, o Java alcança a independência de plataforma.A linguagem Java não precisa ser recompilada ao ser executada em plataformas diferentes, bastando implantar a JVM na plataforma. Portanto, é possível compilar e executar em vários locais ao mesmo tempo. (Assim como sua máquina virtual também pode rodar em qualquer sistema com VMWare instalado)

 

2. JRE e JDK

JRE: Java Runtime Environment, ou seja, a plataforma operacional da JVM, em relação à máquina virtual utilizada no dia a dia, pode ser entendida como JRE = plataforma da máquina virtual + corpo da máquina virtual (JVM). Semelhante ao VMWare no seu computador + máquina virtual Ubuntu para VMWare. Desta forma, também entendemos o que é a JVM.

 

JDK: Java Development Kit, um kit de ferramentas de desenvolvimento Java. O corpo do JDK também é um programa Java, portanto a operação depende do JRE. Devido à necessidade de manter a independência e integridade do JDK, o diretório de instalação do JDK geralmente também possui um JRE. No momento, a ferramenta de instalação do JDK no Windows fornecida pela Oracle instalará um JRE normal e um JRE no diretório JDK ao mesmo tempo.

 

3. Estrutura da JVM

JVM inclui principalmente: contador de programa (Contador de Programa), heap Java (Heap), pilha de máquina virtual Java (Pilha), pilha de método local (Pilha Nativa), área de método (Área de Método)

 

A estrutura detalhada é a seguinte:

 

 

 

Agora deixe-me apresentar a função de cada parte separadamente.

 

3.1. Contador de Programa (PC, Contador de Programa)

É um registrador, que pode ser considerado como um indicador de número de linha de código, semelhante ao PC de um computador real, usado para indicar e pular para o próximo comando que precisa ser executado. As operações básicas de Java e o tratamento de exceções são muito dependentes do PC.

 

O multithreading da JVM é realizado alternando os threads e alocando o tempo de execução do processador. Em um determinado momento, um processador (ou um núcleo de um processador multi-core) executará apenas comandos em um thread. Portanto, para alternar os threads normalmente, cada thread terá um PC independente e os PCs de cada thread não afetarão uns aos outros. A memória ocupada por este PC privado é a "memória privada" do thread.

 

Se o thread estiver executando um método Java, o PC registra o endereço da instrução de bytecode da máquina virtual em execução. Se não for um método Java, ou seja, um método Nativo, o valor de PC é indefinido.

 

A região de memória do PC é a única região na Java Virtual Machine Specification que não especifica nenhum OutOfMemoryError.

 

3.2. Pilhas de Máquina Virtual Java (Pilha, Pilhas de Máquina Virtual Java)

Como o PC (podemos ver no fluxograma de trabalho, de fato, o PC também existe na JVM Stack), ele também é privado para o thread e seu ciclo de vida é o mesmo do thread. A pilha da máquina virtual descreve o modelo de memória da execução do método Java. Quando cada método é executado, um quadro de pilha (Stack Frame) será criado. O quadro de pilha usará o array de variáveis ​​locais para armazenar variáveis ​​locais (Variáveis ​​locais), pilha de operação (Pilha de operandos), método Export (Valor de retorno), conexão dinâmica (Referência de pool de constantes de classe atual) e outras informações.

 

A matriz de variáveis ​​locais armazena oito tipos básicos (int, boolean, char, short, byte, long, float, double) conhecidos por compilação, referência de objeto (de acordo com diferentes implementações de máquinas virtuais, pode ser um ponteiro para um endereço de referência ou um identificador), tipo returnAddress. 64 bits long e double ocuparão dois slots e outros tipos ocuparão um slot. Durante a compilação, o espaço exigido pelas variáveis ​​locais será alocado e o espaço necessário não será alterado durante a operação dinâmica.

 

A pilha de operação será usada ao executar instruções de bytecode. Este método é semelhante aos registradores nativos da CPU. A maioria das JVMs gasta tempo na pilha de operação. A pilha de operação e os arrays de variáveis ​​locais frequentemente trocam dados.

 

A vinculação dinâmica controla a vinculação do conjunto de constantes de tempo de execução e dos quadros de pilha. Todas as referências de método e classe são armazenadas no pool de constantes como referências simbólicas. Referências simbólicas são referências lógicas que na verdade não apontam para endereços de memória física. A JVM pode escolher o tempo de resolução da referência do símbolo. Uma delas é quando o arquivo de classe é carregado e verificado. Esse método de resolução é chamado de método starvation. A outra é que a referência do símbolo é resolvida quando é usada pela primeira vez.Este método de resolução é chamado de método preguiçoso. Em qualquer caso, a JVM deve concluir a resolução e lançar um possível erro de resolução na primeira vez que uma referência simbólica for usada. Binding é o processo de substituição de referências simbólicas a campos, métodos e classes de objetos por referências diretas. A vinculação acontecerá apenas uma vez. Uma vez vinculadas, as referências simbólicas são completamente substituídas. Se uma referência simbólica a uma classe não for resolvida, a classe será carregada. Cada referência direta é armazenada como um deslocamento relativo à estrutura de armazenamento associada ao local da variável ou método em tempo de execução.

 

Para a área da pilha da máquina virtual Java, a especificação da máquina virtual Java especifica duas exceções:

 

Se a profundidade da pilha solicitada pelo thread for maior que a profundidade permitida pela máquina virtual, uma exceção StackOverFlow será lançada.

Para uma máquina virtual que oferece suporte à expansão dinâmica, uma exceção OutOfMemory será lançada quando a expansão falhar ao aplicar para memória suficiente.

3.3. Pilha Nativa

Como o próprio nome sugere, a pilha de métodos nativos é, na verdade, muito semelhante à pilha de máquinas virtuais Java, exceto pelo fato de executar o método nativo e servir ao método nativo. Na especificação da JVM, não há provisão específica para sua implementação.

 

3.4. Java 堆 (Heap, Garbage Collection Heap)

 

 

O heap Java é uma área compartilhada por todos os encadeamentos e é criado quando a máquina virtual é iniciada. O único propósito desta área de memória é armazenar instâncias de objetos, e quase todas as instâncias de objetos alocam memória aqui (com o desenvolvimento da tecnologia, isso não é absoluto).

 

O heap Java é a principal área gerenciada pelo coletor de lixo, por isso também é chamado de heap GC. O coletor adota o método de recuperação geracional, e a pilha GC pode ser dividida em geração jovem (geração jovem) e geração antiga (geração antiga). A nova geração inclui Eden Space e Survivor Space. Mas não importa qual área ou como ela é dividida, todas as instâncias de objetos Java são armazenadas e a divisão posterior é para recuperar melhor a memória ou alocar memória rapidamente.

 

De acordo com a especificação da máquina virtual Java, a faixa de memória física onde o heap está localizado pode ser descontínua, desde que a lógica seja contínua. As implementações podem ser de tamanho fixo ou escaláveis. Se o heap não puder ser expandido, um OutOfMemoryError será gerado.

 

3.5. Área de Método

A área do método é semelhante ao heap Java e também pertence à área de memória compartilhada por cada encadeamento. Usado para armazenar informações de classe carregadas pela máquina virtual, constantes, variáveis ​​estáticas, dados de código compilados pelo compilador just-in-time, etc. Pertence à área não heap (Non Heap), que é separada da área heap Java. Para uma máquina virtual (HotSpot) com o conceito de geração permanente (Permanent), a área do método existe na geração permanente. A especificação da máquina virtual Java tem regulamentos muito vagos na área de método e até mesmo o GC pode não ser implementado. No entanto, os dados que entram na área do método não existem permanentemente, a recuperação da memória nesta área é principalmente a recuperação do pool de constantes e o descarregamento dos tipos. A má reciclagem dessa área também pode levar a sérios vazamentos de memória.

 

OutOfMemoryError também será lançado quando a área do método não puder atender aos requisitos de alocação de memória.

 

3.6. Cache de Código

Usado para compilar e armazenar métodos que são compilados em código nativo pelo compilador JIT.

 

3.7. Informações de Classe (Dados de Classe)

As informações de classe são armazenadas na área de método, que é composta principalmente por um pool de constantes de tempo de execução (Run-Time Constant Pool) e um método (Method Code).

 

Um arquivo de classe compilado inclui a seguinte estrutura:

 

explicação da estrutura

magic, minor_version, major_version As informações de versão do arquivo de classe e a versão JDK usada para compilar esta classe.

constant_pool é semelhante a uma tabela de símbolos, embora contenha mais dados. Há descrições mais detalhadas abaixo.

access_flags fornece uma lista de descritores para esta classe.

this_class fornece o índice constant_pool do nome completo desta classe, por exemplo, org/jamesdbloom/foo/Bar.

super_class Fornece o índice de pool constante das referências de símbolo de classe pai desta classe.

interfaces Aponta para uma matriz de índices no pool constante, fornecendo referências simbólicas para essas interfaces implementadas.

campos Uma matriz de índices de pool constantes que fornecem uma descrição completa de cada campo.

métodos aponta para uma matriz de índices no constant_pool representando uma descrição completa de cada assinatura de método. Se o método não for abstrato nem nativo, o bytecode da função será exibido.

atributos Uma matriz de valores diferentes, indicando informações adicionais dessa classe, incluindo anotações RetentionPolicy.CLASS e RetentionPolicy.RUNTIME.

3.8. Conjunto de Constantes de Tempo de Execução

O conjunto de constantes de tempo de execução faz parte da área de método. O arquivo Class contém informações de descrição, como a versão da classe, campos, métodos e interfaces, e é usado para armazenar várias referências literais e simbólicas geradas durante a compilação. Essa parte do conteúdo será armazenada no pool de constantes de tempo de execução na área de métodos após o carregamento da classe. A especificação da máquina virtual Java possui requisitos estritos sobre os detalhes da Classe e não requer a implementação do conjunto de constantes de tempo de execução. De um modo geral, além da classe traduzida, a referência direta traduzida também existirá no conjunto de constantes de tempo de execução.

 

O conjunto de constantes de tempo de execução é dinâmico, ou seja, novas constantes também podem ser colocadas no conjunto em tempo de execução. Por exemplo, o método intern() da classe String.

 

OutOfMemoryError também será lançado quando o pool constante não puder ser aplicado para alocação de memória suficiente.

 

3.9. Memória Direta

A memória direta não está na Java Virtual Machine Specification e não faz parte do Java, mas é usada com frequência e pode causar OutOfMemoryError. A biblioteca de funções Native pode alocar memória fora do heap diretamente e usar o objeto DirectDataBuffer armazenado no heap Java como uma referência a essa memória. Fazer isso pode melhorar significativamente o desempenho em alguns cenários.

 

A memória direta é uma memória fora do heap, que naturalmente não é limitada pelo tamanho do heap Java, mas pode ser limitada pelo tamanho da memória física da máquina. Se a soma de cada parte da memória for maior que a memória da máquina física, também será reportado um OutOfMemoryError.

 

4. Coleta de lixo Java

Recicle objetos que não são mais usados ​​na memória. O método usado para reciclar no GC é chamado de coletor. Como o GC precisa consumir alguns recursos e tempo, após analisar as características do ciclo de vida dos objetos, o Java usa nova geração, antigo O objeto é coletados no caminho da geração, de forma a encurtar ao máximo a pausa causada pelo GC à aplicação.

 

Diferentes tipos de referência de objeto, o GC usará métodos diferentes para reciclar, as referências de objeto JVM são divididas em quatro tipos:

 

Referência forte: Por padrão, todos os objetos usam referências fortes (a instância deste objeto não possui outras referências de objeto e será reciclada durante o GC).

Referência suave: Referência suave é um aplicativo fornecido em Java que é mais adequado para cenários de cache (somente quando a memória não for suficiente será GC).

Referência fraca: será recuperada pelo GC durante o GC.

Referência fantasma: Porque a referência fantasma é usada apenas para saber se o objeto é GC.

5. A relação entre encadeamentos da JVM e encadeamentos nativos

A JVM permite que um programa use vários encadeamentos simultâneos. Os encadeamentos Java no Hotspot JVM são mapeados diretamente para os encadeamentos do sistema operacional nativo. Isto é, quando o armazenamento local da thread, alocação de buffer, objetos de sincronização, pilhas, contadores de programa, etc. estiverem prontos, uma thread nativa do sistema operacional será criada. Quando o encadeamento Java termina, o encadeamento nativo é reciclado. O sistema operacional é responsável por agendar todos os threads e atribuí-los a qualquer CPU disponível. Quando o encadeamento nativo é inicializado, o método run() do encadeamento Java é chamado. Quando run() retorna, a exceção não detectada é tratada e o encadeamento nativo verificará se deve encerrar o processo JVM devido à sua conclusão (por exemplo, este encadeamento é o último encadeamento não daemon). Quando o encadeamento termina, todos os recursos do encadeamento nativo e do encadeamento Java são liberados.

おすすめ

転載: blog.csdn.net/weixin_57763462/article/details/131691673