2. Quais áreas estão incluídas na área de dados de tempo de execução?
3. Quais dados são armazenados na pilha e no heap, respectivamente?
4. Por que deveríamos substituir a geração permanente (PermGen) pelo metaespaço (MetaSpace)?
5. Você entende a estrutura básica do espaço heap? Em que circunstâncias um objeto entrará na geração antiga?
6. Em que área da memória são colocados os objetos grandes?
7. Qual é o processo de criação de objetos Java?
Resposta da questão
1. Em que partes consiste a JVM?
Resposta: JVM é um executávelbytecódigo (.class) computador virtual de arquivo, que também fornece gerenciamento de memória, coleta de lixo e outros mecanismos. Ele contém as seguintes partes principais.
Subsistema de carregamento de classes: Responsável por carregar arquivos de bytecode (.class) na JVM.
Área de dados de tempo de execução: é a área de memória utilizada pela JVM durante a execução.
Mecanismo de execução: Responsável por interpretar ou compilar bytecode em código de máquina para execução do processador.
Interface de biblioteca nativa: fornece um conjunto de APIs para chamar bibliotecas nativas escritas no sistema operacional ou em outras linguagens.
2. Quais áreas estão incluídas na área de dados de tempo de execução?
Resposta: A área de dados de tempo de execução é a área de memória alocada pela JVM ao executar um programa Java.
Contador de programa: É um pequeno espaço de memória e é o endereço da instrução de bytecode que está sendo executada pelo thread. Se o thread estiver executando um método nativo, o valor desse contador será indefinido.
Pilha de máquina virtual Java: cada thread criará uma pilha de máquina virtual quando for criada, que é usada para armazenar a tabela de variáveis locais do thread, quadro de operando, link dinâmico, informações de saída de método, etc. A pilha da máquina virtual Java contém vários quadros de pilha. O processo de cada método chamado até a conclusão da execução corresponde ao processo de empurrar um quadro de pilha para a pilha da máquina virtual.
Pilha de métodos nativos: É o espaço preparado pela JVM para executar métodos nativos. Possui funções semelhantes à pilha da máquina virtual Java. É um modelo de memória que descreve o processo de execução de métodos nativos.
Heap: usado para armazenar quase todas as instâncias e arrays de objetos, e é a principal área onde funciona o coletor de lixo.
Área de métodos: usada para armazenar informações de classe, constantes, variáveis estáticas, código compilado pelo compilador just-in-time, etc. carregado pela JVM. Antes do JDK1.8, ele era implementado como uma geração permanente. A partir do JDK1.8, a geração permanente é substituída pelo espaço original. O Metaspace usa memória local em vez de memória heap.
3. Quais dados são armazenados na pilha e no heap, respectivamente?
Resposta: Dados armazenados na pilha (pilha de máquinas virtuais Java):
Tabela de variáveis locais: usada principalmente para armazenar parâmetros de métodos e variáveis locais dentro do método, incluindo tipos de dados básicos e referências de objetos.
Pilha de operandos: usada para armazenar temporariamente instruções de operação e resultados intermediários durante a execução do método.
Link dinâmico: uma referência ao conjunto de constantes da classe à qual o método pertence, usada para resolver referências de símbolos no método.
Endereço de retorno do método: armazena o endereço da próxima instrução executada após a chamada do método. Dados armazenados no heap:
Instância de objeto: uma instância de objeto criada por meio da palavra-chave new no programa, incluindo as propriedades e métodos do objeto.
Matriz: todos os tipos de matrizes, incluindo matrizes de tipo básico e matrizes de objetos.
4. Por que deveríamos substituir a geração permanente (PermGen) pelo metaespaço (MetaSpace)?
Resposta: Substituir a geração permanente pelo metaespaço visa principalmente resolver alguns problemas e limitações inerentes à geração permanente e melhorar o desempenho e flexibilidade da JVM.
Melhore a flexibilidade e eficiência do gerenciamento de memória: O tamanho da memória da geração permanente é definido quando a JVM é iniciada e não pode ser ajustado dinamicamente. O Metaspace usa memória local em vez de memória heap Java e seu tamanho pode ser ajustado dinamicamente conforme necessário.
Resolva o problema de descarga de classe e coleta de lixo: o comportamento do GC da geração permanente é complexo e imprevisível e a eficiência de reciclagem é baixa.
Fornece melhor desempenho e estabilidade: O uso do metaespaço torna o gerenciamento de memória JVM mais unificado e consistente, porque o metaespaço, como outras áreas de memória, é gerenciado usando memória local. Isso simplifica as estratégias de gerenciamento de memória e melhora o desempenho e a estabilidade gerais.
Simplifique o gerenciamento de memória JVM
5. Você entende a estrutura básica do espaço heap? Em que circunstâncias um objeto entrará na geração antiga?
Resposta: A estrutura básica do espaço heap é composta principalmente pela nova geração, pela geração antiga e pela geração permanente. Após o JDK8, a geração permanente é substituída pelo metaespaço e usa memória local para armazenamento.
Geração Cenozóica: O progresso da nova geração é subdividido na área do Éden e em duas áreas de sobreviventes (Sobrevivente 0 e Sobrevivente 1)
Área Eden: Os objetos recém-criados primeiro alocam memória na área Eden.
Área sobrevivente (S0, S1): utilizada para armazenar objetos que sobreviveram à coleta de lixo da nova geração. Após cada GC Menor, os objetos sobreviventes serão copiados entre essas duas áreas.
Geração antiga: Objetos que ainda estão vivos após vários GCs secundários. A coleta de lixo (GC Principal ou GC Completo) é realizada com menos frequência na geração antiga.
Geração/metaespaço permanente: usado para armazenar metadados de classes, incluindo definições de classe, constantes, variáveis estáticas, código compilado just-in-time, etc.
A situação quando o objeto está na geração antiga:
O limite de idade é atingido: Cada objeto tem uma idade quando a memória é alocada na nova geração, e a idade será aumentada em 1 após cada GC Menor. Quando a idade atingir um determinado limite (o padrão é 15), o objeto será promovido para a geração antiga.
Objeto grande: Se o objeto for muito grande e exceder o limite definido pela JVM, o objeto alocará espaço diretamente na geração antiga.
Espaço insuficiente na área do Sobrevivente: Se a área do sobrevivente não tiver espaço suficiente para acomodar todos os objetos sobreviventes durante o GC Menor, esses objetos serão
Determinação dinâmica da idade do objeto: Se o tamanho de todos os objetos da mesma idade no espaço Sobrevivente exceder metade do espaço Sobrevivente, então os objetos cuja idade seja maior ou igual a esta idade podem entrar diretamente na geração antiga.
// 动态年龄计算代码
uint ageTable::compute_tenuring_threshold(size_t survivor_capacity){//survivor_capacity是survivor空间的大小size_t desired_survivor_size =(size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100);//TargetSurvivorRatio 为50size_t total =0;
uint age =1;while(age < table_size){
total += sizes[age];//sizes数组是每个年龄段对象大小if(total > desired_survivor_size)break;
age++;}
uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold;...}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
6. Em que área da memória são colocados os objetos grandes?
Resposta: Objetos grandes (matrizes e strings muito grandes) geralmente são alocados diretamente na área de memória da geração antiga.Isto é para evitar que a nova geração realizeColeta de lixoNeste momento, objetos grandes são frequentemente copiados entre a área Eden e a área Survivor, melhorando assim a eficiência da coleta de lixo. Configure o limite para objetos grandes entrarem diretamente na geração antiga:
Se a classe não tiver sido carregada, conectada e inicializada, a JVM carregará a classe primeiro. Isso inclui as seguintes etapas:
Carregando: Leia o arquivo da classe por meio do carregador de classes e carregue o bytecode da classe na memória.
Conexão: inclui três etapas: verificação, preparação e análise. Verifique a exatidão dos arquivos de classe, prepare variáveis estáticas da classe e aloque memória e resolva referências de símbolos em referências diretas.
Inicialização: Executa o bloco de inicialização estática da classe e a inicialização das variáveis estáticas.
alocação de memória
A JVM aloca memória para novos objetos no heap. O tamanho da memória alocada é determinado pela estrutura do objeto, incluindo o cabeçalho do objeto e os dados da instância.
A JVM possui duas maneiras principais de alocar memória:
Bump-the-pointer: Se a memória heap for regular, o ponteiro de alocação só precisa se mover uma distância especificada até a área de memória livre.
Lista Livre: Se a memória heap for irregular, a JVM precisa manter uma lista livre e encontrar o bloco apropriado na lista livre ao alocar memória.
inicializar com valor zero
A JVM inicializará todas as variáveis de instância do objeto com seus valores padrão. Por exemplo, variáveis de tipo numérico serão inicializadas como 0, variáveis de tipo booleano como false e variáveis de tipo de referência como null.
Definir cabeçalho do objeto
Defina as informações do cabeçalho do objeto no espaço de memória do objeto, que inclui o código hash do objeto, idade de geração do GC, sinalizador de status de bloqueio, bloqueio mantido pelo thread, ID do thread tendencioso, etc.
Inicialização do construtor
Chame o construtor do objeto para concluir a inicialização do objeto. Isso inclui a execução de operações de inicialização explícitas em variáveis de instância, bem como em código no corpo do construtor. As etapas específicas são as seguintes:
Execute o bloco de inicialização da instância da classe.
Execute o método construtor da classe pai de cima para baixo de acordo com a hierarquia de herança.
Inicialize variáveis de instância com valores especificados explicitamente.
Execute a parte principal do método construtor da classe.