Prefácio
Classifique o processo de criação de objetos e o processo de inicialização
Processo de criação de objetos
- Quando a nova instrução é usada, localize a referência de símbolo do parâmetro da instrução no pool constante
- Caso contrário, carregue, conecte e inicialize a classe.
- A máquina virtual aloca memória para objetos recém-nascidos
- Inicialize o espaço de memória alocado para zero, excluindo o cabeçalho do objeto, e inicialize o cabeçalho do objeto (código hash, idade gc, etc.)
- Método de objeto de chamada
1. Processo de carregamento de classe
2. Layout da memória do objeto
O layout dos objetos na memória é dividido em três áreas: cabeçalho do objeto, dados da instância e preenchimento de alinhamento.
1. Cabeça do objeto
O cabeçalho do objeto da máquina virtual Hotspot inclui principalmente duas partes de dados: Mark Word (campo marcado) e Klass Pointer (tipo de ponteiro). O array terá 1 palavra de largura (32 bits: 4 bytes) para armazenar o comprimento do array .
- Mark Word é usado para armazenar os dados de tempo de execução do próprio objeto, é a chave para realizar o bloqueio leve e o bloqueio de polarização.
- Klass Point é o ponteiro do objeto para os metadados de sua classe.A máquina virtual usa esse ponteiro para determinar qual instância de classe o objeto é;
2. Dados de exemplo
Esta parte é a informação efetiva que o objeto realmente armazena e também é o conteúdo de vários tipos de campos definidos no código do programa, incluindo aqueles herdados da classe pai e aqueles definidos na subclasse.
3. Alinhar e preencher
Esta parte não é necessária. Algumas máquinas virtuais requerem que o endereço inicial do objeto seja um múltiplo inteiro de 8 bytes, ou seja, o tamanho do objeto deve ser um múltiplo inteiro de 8 bytes, então o alinhamento é necessário quando for insuficiente.
4. Explicação detalhada de Mark Word
Existem duas maneiras de cabeçalho de objeto na JVM (tome a JVM de 32 bits como exemplo):
// 普通对象
|--------------------------------------------------------------|
| Object Header (64 bits) |
|------------------------------------|-------------------------|
| Mark Word (32 bits) | Klass Word (32 bits) |
|------------------------------------|-------------------------|
// 数组对象
|---------------------------------------------------------------------------------|
| Object Header (96 bits) |
|--------------------------------|-----------------------|------------------------|
| Mark Word(32bits) | Klass Word(32bits) | array length(32bits) |
|--------------------------------|-----------------------|------------------------|
Esta parte do Mark Word é usada principalmente para armazenar os dados de tempo de execução do próprio objeto, como hashcode, idade de geração do gc, sinalizador de status de bloqueio, bloqueio mantido pelo encadeamento, ID do encadeamento tendencioso, carimbo de data / hora tendencioso, etc.
O comprimento de bit da palavra de marca é o tamanho de uma palavra da JVM, o que significa que a palavra de marca de uma JVM de 32 bits é de 32 bits e uma JVM de 64 bits é de 64 bits.
O Mark Word foi projetado como uma estrutura de dados não fixa para armazenar o máximo de dados possível em um espaço de memória muito pequeno. Ele reutiliza seu próprio espaço de armazenamento de acordo com o estado do objeto. Para armazenar mais informações em um tamanho de palavra, JVM will Os dois bits mais baixos da palavra são definidos como bits de marca, e a palavra de marca sob diferentes bits de marca é mostrada como segue:
|-------------------------------------------------------|--------------------|
| Mark Word (32 bits) | State |
|-------------------------------------------------------|--------------------|
| identity_hashcode:25 | age:4 | biased_lock:0 |lock:01 | Normal无锁 |
|-------------------------------------------------------|--------------------|
| thread:23 | epoch:2 | age:4 | biased_lock:1| lock:01 | Biased偏向锁 |
|-------------------------------------------------------|--------------------|
| ptr_to_lock_record:30 | lock:00 | Lightweight Locked轻量级锁 |
|-------------------------------------------------------|--------------------|
| ptr_to_heavyweight_monitor:30 | lock:10 | Heavyweight Locked重量级锁 |
|-------------------------------------------------------|--------------------|
| | lock:11 | Marked for GC GC标记|
|-------------------------------------------------------|--------------------|
- bloqueio: bit de sinalizador de status de bloqueio de 2 bits. Como queremos usar o mínimo possível de bits binários para representar o máximo de informações, o sinalizador de bloqueio está definido. O valor da marca é diferente, o significado de toda a palavra da marca é diferente.
- bised_lock: se o objeto habilita o sinalizador de bloqueio polarizado, que ocupa apenas 1 bit binário. Quando for 1, significa que o objeto possui um bloqueio polarizado; quando for 0, significa que o objeto não possui um bloqueio polarizado.
- idade: idade do objeto Java de 4 dígitos. No GC, se o objeto for copiado uma vez na área do sobrevivente, a idade aumenta em 1. Quando o assunto atinge o limite definido, ele será promovido à velhice. Por padrão, o limite de idade para GC paralelo é 15 e o limite de idade para GC simultâneo é 6. Como a idade tem apenas 4 bits, o valor máximo é 15, razão pela qual o valor máximo da opção -XX: MaxTenuringThreshold é 15.
- Identity_hashcode: código hash de identificação de objeto de 25 bits, usando tecnologia de carregamento lento. Chame o método System.identityHashCode () para calcular e gravar o resultado no cabeçalho do objeto. Quando o objeto estiver bloqueado, o valor será movido para o monitor monitor.
- thread: O ID do thread que contém o bloqueio de polarização.
- epoch: bias timestamp.
- ptr_to_lock_record: Ponteiro para o registro de bloqueio na pilha.
- ptr_to_heavyweight_monitor: Ponteiro para monitorar o monitor.
3. Sequência de inicialização do objeto
De acordo com o processo de carregamento da classe, a inicialização da classe clinit
é executada primeiro e, em seguida, o init
método de inicialização do objeto é executado. A sequência é a seguinte:
-
Variável estática da classe pai Variável
estática da subclasse -
Bloco de código estático da classe pai Bloco de
código estático da classe filha -
Bloco de método de
classe pai Construtor de classe pai -
Construtor de subclasse de bloco de método de subclasse
3. Local de acesso ao objeto
Atualmente, existem duas formas principais de acesso:
-
O identificador
precisa de uma memória separada do heap como o pool de identificadores, mas a vantagem é que a referência armazena um endereço de identificador estável e apenas o ponteiro de instância no identificador é alterado quando o objeto é movido devido ao GC.
-
O ponteiro direto tem a
vantagem de ser rápido
A partir disso, sabemos a que os objetos referenciados na pilha da máquina virtual (tabela de variável local no frame da pilha) se referem nas raízes do GC.
Conclusão
Este artigo analisa o processo geral de criação de objetos, que é de grande ajuda para entender a máquina virtual.