Cabeçalho do objeto Java

Você já se perguntou como são os objetos java por dentro?
Abaixo do corte, há uma descrição detalhada do cabeçalho do objeto java, em que consiste e quanta memória é necessária.


Para começar, lembramos que, na jvm, qualquer objeto na memória consiste em um cabeçalho e variáveis ​​de objeto (links e primitivas). Além disso, o tamanho final do objeto pode ser expandido para se tornar um múltiplo de 8 bytes.


O título de cada objeto (exceto a matriz) consiste em duas palavras de máquina - marcar a palavra e a palavra da classe . As matrizes têm 32 bits adicionais para descrever o comprimento da matriz.


A marca Mark armazena o código hash da identidade, os bits usados ​​pelo coletor de lixo e os bits usados ​​para bloqueios. Você sempre pode encontrar mais detalhes na classificação correspondente do OpenJDK, markOop.hpp .


Uma palavra de classe armazena um ponteiro para a própria classe, ou seja, para o local onde estão as informações sobre esse tipo de dados: métodos, anotações, herança e muito mais. Mais detalhes também podem sempre ser encontrados nos tipos correspondentes do OpenJDK, klass.hpp .


Vamos agora dar uma olhada no título do objeto e , em particular, marcar a palavra


Jvm de 32 bits


JVM de 32 bits


Como você pode ver na tabela, o conteúdo da palavra Mark pode variar bastante, dependendo do estado atual do objeto.


Estado normal do objeto (bloqueio parcial = 0, bloqueio = 01)


  • identity_hashcode é o hash de um objeto que aparece preguiçosamente. Se o objeto tiver uma chamada System.identityHashCode (obj) pela primeira vez, esse hash será calculado e gravado no cabeçalho do objeto.
    Em outros estados, quando vários fluxos competem por um objeto, o identity_hashcode será armazenado não no cabeçalho do objeto, mas no monitor do objeto.
  • idade - o número de coletas de lixo experimentadas. Quando a idade atinge o número do limite máximo de posse,
    o objeto se move para a área do quadril da geração antiga.
  • bided_lock - contém 1 se o bloqueio polarizado estiver ativado para este objeto, caso contrário, 0.

Um pouco mais
Quando o bloqueio polarizado está ativado, o objeto se move como se estivesse no primeiro objeto que capturou seu monitor. A captura subsequente do objeto no mesmo fluxo será um pouco mais rápida.

Aqui estão os pré-requisitos teóricos básicos para esse bloqueio:
  • Ao longo da vida de um objeto, ele pertence predominantemente a um fluxo
  • Se o encadeamento usou recentemente um bloqueio nesse objeto, provavelmente o cache do processador ainda conterá os dados necessários para capturar novamente esse objeto.


O bloqueio polarizado é ativado por padrão, pois java 6, -XX: -UseBiallyLocking

  • bloqueio - contém o código de status do bloqueio. 00 - Bloqueado leve, 01 - Desbloqueado ou enviesado, 10 - Bloqueado pesado, 11 - Marcado para coleta de lixo.

Ou seja, na tabela, o estado de um objeto é determinado pela combinação de bits enviesados ​​e de bloqueio.


Modo bloqueado enviesado (bloqueio enviesado = 1, bloqueio = 01)


  • No modo de bloqueio tendencioso do encadeamento, assume-se que o objeto pertence predominantemente a um encadeamento específico, o ID desse encadeamento é armazenado no campo.
  • época contém algum indicador temporário de propriedade do objeto por um encadeamento cujo ID é armazenado no encadeamento

Modo Bloqueado Leve (bloqueio = 00)


Nesse modo, supõe-se que o tempo de captura desse objeto por diferentes fluxos não se cruze ou não se sobreponha de forma insignificante. Nesse modo, em vez de bloquear pesado o sistema operacional, a JVM usa atômica.


  • ptr_to_lock_record - CAS (comparar e definir) dentro do loop de rotação é usado para definir / aguardar um bloqueio.
    Para referência, o tempo mínimo de bloqueio do sistema operacional será de aproximadamente 10 ms, com a ajuda de atômicos, o fluxo não adormecerá, mas continuará a trilhar um pequeno ciclo e, assim que o recurso estiver livre, o ciclo atômico terminará e o fluxo capturará imediatamente esse objeto.

Modo Bloqueado Pesado (bloqueio = 10)


  • ptr_to_heavyweight_monitor - se o tempo de captura desse objeto com fluxos diferentes se sobrepor significativamente, o bloqueio leve será substituído por um bloqueio pesado. Um ponteiro para o monitor será gravado em ptr_to_heavyweight_monitor. O bloqueio do sistema operacional é usado.

Portanto, na jvm de 32 bits, o cabeçalho do objeto consiste em 8 bytes. Matrizes também possuem 4 bytes.


Jvm de 64 bits


JVM de 64 bits


Em uma jvm de 64 bits, o cabeçalho do objeto consiste em 16 bytes. Matrizes também possuem 4 bytes.


Jvm de 64 bits com compactação de ponteiro


Coop JVM de 64 bits


Um cabeçalho de objeto consiste em 12 bytes. Matrizes também possuem 4 bytes.


Um pouco sobre a compactação do ponteiro. Para um ponteiro de 32 bits, o espaço de endereço é limitado a 4 GB. No entanto, se lembrarmos novamente que, na jvm, o tamanho de um objeto é múltiplo de 8 bytes, podemos usar um ponteiro pseudo-35 bits, com três zeros no final. E, portanto, consulte já 32 GB de memória. A compactação não é gratuita, o preço é uma operação adicional (ponteiro << 3) para qualquer chamada para heap.


Link para o artigo original:


Cabeçalho de Objeto Java


Eu também gostaria de acrescentar que tudo o que é descrito aqui não é um dogma, talvez em outras versões da jvm o título do objeto seja diferente. Descrito aqui é relevante para o openjdk 8.

Source: https://habr.com/ru/post/pt447848/


All Articles