Compreensão profunda do quadro de jvm-stack e chamada de método

Este artigo é uma nota de leitura

1. Conceitos básicos

Insira a descrição da imagem aqui
A máquina virtual Java usa métodos como a unidade de execução mais básica . "Frame da pilha" é uma estrutura de dados usada para suportar a invocação de métodos e a execução de métodos da máquina virtual.É também a máquina virtual na área de dados do tempo de execução da máquina virtual. Elemento de pilha da pilha da máquina virtual.

** Composição básica: ** Tabela de variáveis ​​locais, pilha de operandos, link dinâmico, endereço de retorno do método e algumas informações adicionais adicionais.

Ao compilar o código-fonte do programa Java , quanta tabela de variáveis ​​locais é necessária no quadro da pilha, qual a profundidade da pilha do operando precisa ser analisada e calculada e gravada na propriedade Código da tabela de métodos

Da perspectiva de um programa Java, todos os métodos na pilha de chamadas estão no mesmo estado, ao mesmo tempo e no mesmo encadeamento. Para o mecanismo de execução, no encadeamento ativo, apenas o método na parte superior da pilha está em execução e apenas o quadro da pilha na parte superior da pilha é efetivo , chamado ** "quadro atual da pilha" ** ( CurrentStack Frame), o método associado a esse quadro de pilha é chamado "Método Atual".

Há uma parte no código fonte do springboot:

Esta parte está no método de construção de SpringApplication.class, a classe que obtém a entrada do método principal, sua operação é obter o quadro de pilha atual; a depuração pode ver claramente que o
Insira a descrição da imagem aqui
processo básico do quadro de pilha atual é criar uma exceção de tempo de execução e, em seguida, obter o array de pilha, atravessar StackTraceElement, julgue se o nome do método é "mian"; se sim, crie o objeto Class pelo método Class.forName ().

O código é muito simples, mas o uso do SpringBoot nos faz sentir muito esclarecedores. Vamos comparar o tratamento de exceções do Java e aprender mais sobre o uso do StackTrace.

Stacktrace (rastreamento de pilha) é uma ferramenta de depuração muito útil. Quando uma exceção ocorre no programa ou gera uma exceção manualmente, o local do erro pode ser exibido, causando o relacionamento hierárquico do erro.

2. Tabela Variável Local

Espaço de armazenamento para armazenar parâmetros do método e variáveis ​​locais definidas dentro do método.
Quando o programa Java é compilado em um arquivo de Classe, a capacidade máxima da tabela de variáveis ​​locais que o método precisa alocar é determinada no item de dados max_locals do atributo Code do método.

Para booleano de 32 bits, byte, char, short, int, float, reference [illustration] e returnAddress, um slot é suficiente.
Para tipos de dados de 64 bits, a máquina virtual Java aloca dois espaços de slot variáveis ​​consecutivos de maneira alinhada por bits altos.

A máquina virtual Java usa a tabela de variáveis ​​locais por meio do posicionamento do índice . ** O intervalo do valor do índice é de 0 ao número máximo de slots de variáveis ​​na tabela de variáveis ​​locais. ** Se você estiver acessando uma variável do tipo de dados de 32 bits, o índice N representa o uso do slot de variável N. Se você estiver acessando uma variável do tipo de dados de 64 bits, significa que serão utilizadas as variáveis ​​Nth e N + 1. Slot.

Quando um método é chamado, a máquina virtual Java usa a tabela de variáveis ​​locais para concluir o processo de transferência do valor do parâmetro para a lista de variáveis ​​de parâmetros, ou seja, a transferência do parâmetro real para o parâmetro formal.

O slot variável na tabela de variáveis ​​locais é reutilizável.Exemplo de
reutilização:
Insira a descrição da imagem aqui
se não houver int a = 0; gc não será acionado e gc será acionado depois que estiver disponível;
motivo:
se o slot variável na tabela de variáveis ​​locais ainda possui algumas informações Referência de objeto de matriz de espaço reservado. Na primeira modificação, embora o código tenha deixado o escopo do espaço reservado, mas depois disso, nenhuma operação de leitura ou gravação na tabela de variáveis ​​local ocorreu, o slot da variável originalmente ocupado pelo espaço reservado não foi reutilizado por outras variáveis Portanto, a tabela de variáveis ​​locais como parte do GC Roots ainda mantém sua associação.

3. Pilha de operando

A pilha de operandos (pilha de operandos) costuma ser chamada de pilha de operações, que é uma pilha de último a entrar, primeiro a sair (LIFO).

Cada elemento da pilha de operandos pode ser qualquer tipo de dados Java, incluindo compridos e duplos. A capacidade da pilha ocupada pelo tipo de dados de 32 bits é 1 e a capacidade da pilha ocupada pelo tipo de dados de 64 bits é 2.

4. Conexão dinâmica

Cada quadro de pilha contém uma referência ao método ao qual o quadro de pilha pertence no pool constante de tempo de execução [ilustração]. Essa referência é mantida para oferecer suporte à conexão dinâmica durante a invocação do método.

5. Endereço de retorno do método

Existem apenas duas maneiras de sair do método: 1. retorne normalmente e retorne o valor ao responsável pela chamada superior 2. lance uma exceção e a exceção não será tratada adequadamente.De maneira
geral, quando o método sai normalmente, o valor do contador de PC do método de chamada pode ser usado como retorno Endereço, o contador da pilha provavelmente salvará esse valor do contador. Quando o método sai de forma anormal, o endereço de retorno é determinado pela tabela do manipulador de exceções e essa parte das informações geralmente não é salva no quadro da pilha.
As operações possíveis ao sair são: restaurar a tabela de variáveis ​​locais e a pilha de operandos do método superior, inserir o valor de retorno (se houver) na pilha de operandos da estrutura da pilha do chamador, ajustar o valor do contador do PC para apontar para a chamada do método Uma instrução após a instrução, etc.

6. Informações adicionais

Informações relacionadas à depuração e coleta de desempenho.Esta parte das informações depende inteiramente da implementação específica da máquina virtual.Geralmente
, conexões dinâmicas, endereços de retorno de método e outras informações adicionais são agrupadas, chamadas de informações do quadro de pilha.

Exemplo: i ++, ++ i

Também chamada de execução de interpretação baseada em pilha

int a = 10;
 int b = a++ + ++a + a--; 
 System.out.println(a); 
 System.out.println(b);

Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
A imagem é proveniente da descriptografia de cavalos escuros da estação b jvm

7. Chamada de método

O processo de compilação do arquivo Class não inclui as etapas de conexão da compilação da linguagem de programação tradicional.Todas as chamadas de método armazenadas no arquivo Class são apenas referências simbólicas, não o endereço de entrada do método no layout de memória de tempo de execução real (ou seja, o diretório direto Referência).

A Java virtual machine suporta os cinco métodos a seguir para chamar instruções de bytecode, a saber: invokestatic. Usado para chamar métodos estáticos.

· Invoca especial. Usado para chamar o método <init> () do construtor de instância, métodos privados e métodos na classe pai.

· Invokevirtual. Usado para chamar todos os métodos virtuais.

· Invocar interface. Usado para chamar métodos de interface, e um objeto que implementa a interface será determinado em tempo de execução.

· Dinâmico invocado. O método referenciado pelo qualificador do ponto de chamada é resolvido dinamicamente no tempo de execução e, em seguida, o método é executado. A lógica de despacho das 4 primeiras instruções de chamada é fixada na máquina virtual Java, e a lógica de despacho da instrução invokedynamic é determinada pelo método de inicialização definido pelo usuário.

Desde que os métodos que podem ser invocados pelas instruções invocestáticas e invocadoras especiais, a única versão de chamada possa ser determinada durante a fase de análise.Há quatro métodos na linguagem Java que atendem a essa condição: métodos estáticos, métodos privados, construtores de instância e métodos de superclasse, além de O método modificado por final (embora seja chamado usando a instrução virtual invokual) , essas cinco chamadas de método resolverão as referências de símbolos em referências diretas ao método quando a classe for carregada . Esses métodos são chamados coletivamente de "Métodos não virtuais", enquanto outros métodos são chamados de "Métodos virtuais".

Despacho

Homem homem = nova Mulher ();
Homem é do tipo estático, Mulher é do tipo dinâmico;

Portanto, a execução de um método é dividida em despacho estático e despacho dinâmico de acordo com o tipo estático à esquerda ou o tipo dinâmico à direita;
** O desempenho mais típico do aplicativo de despacho estático é a sobrecarga de método. ** O envio estático ocorre durante a fase de compilação, portanto, é determinado que a ação de envio estático não é realmente executada pela máquina virtual, motivo pelo qual alguns materiais optam por classificá-lo como "analisar" em vez de "despachar".

O processo de implementação do despacho dinâmico está intimamente relacionado a outra manifestação importante do polimorfismo da linguagem Java-Substituição.

Linguagem digitada dinamicamente

O principal recurso de uma linguagem de tipo dinâmico é que o processo principal de verificação de tipo é
"variáveis ​​não têm tipos, mas valores variáveis ​​têm tipos" em tempo de execução, e não na compilação

A seguir está um método dinâmico dentro do java

O pacote java.lang.invoke executa println () em A

Insira a descrição da imagem aqui

Parece reflexão, mas o
MethodHandle tem muitas semelhanças com o Reflection no uso de métodos e efeitos:

Os mecanismos Reflection e MethodHandle estão essencialmente simulando a invocação de método, mas ** Reflection está simulando a invocação de método no nível do código Java, e MethodHandle está simulando a invocação de método no nível do bytecode. ** Os três métodos findStatic (), findVirtual (), findSpecial () em MethodHandles.Lookup devem corresponder ao comportamento de verificação de permissão de execução dessas instruções de bytecode invokestatic, invokevirtual (e invokeinterface) e invoca special, Esses detalhes de baixo nível não precisam se preocupar ao usar a API do Reflection.

** O objeto java.lang.reflect.Method no Reflection é muito mais do que as informações contidas no objeto java.lang.invoke.MethodHandle no mecanismo MethodHandle. ** A primeira é uma imagem abrangente do método no lado do Java, incluindo a assinatura, o descritor e a representação do lado do Java de vários atributos na tabela de atributos do método, além de informações de tempo de execução, como permissões de execução. Este último contém apenas informações relevantes para a execução do método. Nos termos coloquiais dos desenvolvedores, o Reflection é um peso pesado, enquanto o MethodHandle é leve.

· Como MethodHandle é uma simulação da chamada de instrução de método do bytecode, em teoria, várias otimizações feitas pela máquina virtual nessa área (como a inclusão de método) devem ser suportadas por uma idéia semelhante no MethodHandle (mas atualmente implementada Ele ainda está sendo aprimorado) e é quase impossível implementar diretamente várias medidas de otimização de pontos de chamada chamando métodos por meio de reflexão.

Chame o método ancestral:
MethodHandles.Lookup class é semelhante à aquisição da classe Unsafe, essa classe não é nova
Insira a descrição da imagem aqui

Publicado 37 artigos originais · ganhou elogios 6 · vista 4640

Acho que você gosta

Origin blog.csdn.net/littlewhitevg/article/details/105539789
Recomendado
Clasificación