alocação estática em java - heap, pilha e geração permanente


117

Ultimamente tenho lido muito sobre esquemas de alocação de memória em java, e tem havido muitas dúvidas enquanto leio em várias fontes. Eu reuni meus conceitos e gostaria de passar por todos os pontos e comentá-los. Eu descobri que a alocação de memória é específica da JVM, então devo dizer de antemão que minha pergunta é específica da Sun.

  1. As classes (carregadas pelos carregadores de classe) vão para uma área especial no heap: Geração Permanente
  2. Todas as informações relacionadas a uma classe como o nome da classe, arrays de objetos associados à classe, objetos internos usados ​​pela JVM (como java / lang / Object) e informações de otimização vão para a área de Geração Permanente.
  3. Todas as variáveis ​​de membro estático são mantidas na área de Geração Permanente novamente.
  4. Os objetos ficam em uma pilha diferente: geração jovem
  5. Existe apenas uma cópia de cada método por classe, seja o método estático ou não estático. Essa cópia é colocada na área de Geração Permanente. Para métodos não estáticos, todos os parâmetros e variáveis ​​locais vão para a pilha - e sempre que houver uma invocação concreta desse método, obtemos um novo quadro de pilha associado a ele. Não tenho certeza de onde as variáveis ​​locais de um método estático são armazenadas. Eles estão na pilha da Geração Permanente? Ou apenas sua referência é armazenada na área de Geração Permanente, e a cópia real está em outro lugar (Onde?)
  6. Também não tenho certeza de onde o tipo de retorno de um método é armazenado.
  7. Se os objetos (na geração jovem) precisam usar um membro estático (na geração permanente), eles recebem uma referência para o membro estático && eles recebem espaço de memória suficiente para armazenar o tipo de retorno do método, etc.

Obrigado por passar por isso!

Respostas:


152

Em primeiro lugar, como deve estar claro para você agora, existem muito poucas pessoas que podem confirmar essas respostas por conhecimento de primeira mão. Muito poucas pessoas trabalharam em JVMs HotSpot recentes ou as estudaram com a profundidade necessária para realmente saber. A maioria das pessoas aqui (inclusive eu) está respondendo com base em coisas que viram escritas em outros lugares ou no que inferiram. Normalmente, o que está escrito aqui, ou em vários artigos e páginas da web, é baseado em outras fontes que podem ou não ser definitivas. Freqüentemente, é simplificado, impreciso ou simplesmente errado.

Se você deseja uma confirmação definitiva de suas respostas, você realmente precisa baixar o código fonte OpenJDK ... e fazer sua própria pesquisa lendo e entendendo o código fonte. Fazer perguntas no SO ou vasculhar artigos aleatórios na web não é uma boa técnica de pesquisa acadêmica.

Tendo dito isto ...

... minha pergunta é específica da Sun.

No momento em que esta pergunta foi feita, a Sun Microsystems havia deixado de existir. A questão era, portanto, específica da Oracle. AFAIK, todas as implementações JVM de terceiros atuais (não relacionadas à pesquisa) são portas diretas de uma versão do OpenJDK ou descendentes de outra versão da Sun / Oracle.

As respostas abaixo se aplicam aos lançamentos Oracle Hotspot e OpenJDK, e provavelmente à maioria dos outros também ... incluindo GraalVM.

1) As classes (carregadas pelos carregadores de classe) vão para uma área especial no heap: Geração Permanente.

Antes do Java 8, sim.

A partir do Java 8, o espaço PermGen foi substituído pelo Metaspace. As classes carregadas e compiladas por JIT agora vão para lá. PermGen não existe mais.

2) Todas as informações relacionadas a uma classe como o nome da classe, arrays de objetos associados à classe, objetos internos usados ​​pela JVM (como java / lang / Object) e informações de otimização vão para a área de Geração Permanente.

Mais ou menos, sim. Não tenho certeza do que você quer dizer com algumas dessas coisas. Estou supondo que "objetos internos usados ​​pela JVM (como java / lang / Object)" significa descritores de classe internos da JVM.

3) Todas as variáveis ​​de membro estático são mantidas na área de Geração Permanente novamente.

As próprias variáveis ​​sim. Essas variáveis ​​(como todas as variáveis ​​Java) conterão valores primitivos ou referências de objeto. No entanto, enquanto as variáveis ​​de membro estático estão em um quadro que é alocado no heap permgen, os objetos / matrizes referidos por essas variáveis ​​podem ser alocados em qualquer heap.

4) Os objetos ficam em uma pilha diferente: Geração jovem

Não necessariamente. Objetos grandes podem ser alocados diretamente na geração permanente.

5) Existe apenas uma cópia de cada método por classe, seja o método estático ou não estático. Essa cópia é colocada na área de Geração Permanente.

Supondo que você esteja se referindo ao código do método, então AFAIK sim. Pode ser um pouco mais complicado. Por exemplo, esse código pode existir em bytecode e / ou formas de código nativo em diferentes momentos durante a vida da JVM.

... Para métodos não estáticos, todos os parâmetros e variáveis ​​locais vão para a pilha - e sempre que houver uma invocação concreta desse método, obtemos um novo quadro de pilha associado a ele.

Sim.

... Não tenho certeza de onde as variáveis ​​locais de um método estático são armazenadas. Eles estão na pilha da Geração Permanente? Ou apenas sua referência é armazenada na área de Geração Permanente, e a cópia real está em outro lugar (Onde?)

Não. Elas são armazenadas na pilha, assim como as variáveis ​​locais em métodos não estáticos.

6) Também não tenho certeza de onde o tipo de retorno de um método é armazenado.

Se você quer dizer o valor retornado por uma chamada de método (não nula), então ele é retornado na pilha ou em um registro de máquina. Se for retornado na pilha, leva 1 ou duas palavras, dependendo do tipo de retorno.

7) Se os objetos (na geração jovem) precisam usar um membro estático (na geração permanente), eles recebem uma referência ao membro estático e recebem espaço de memória suficiente para armazenar o tipo de retorno do método, etc. .

Isso é impreciso (ou, pelo menos, você não está se expressando claramente).

Se algum método acessa uma variável de membro estático, o que ele obtém é um valor primitivo ou uma referência de objeto . Isso pode ser atribuído a uma variável local (existente) ou parâmetro, atribuído a um membro estático ou não estático (existente), atribuído a um elemento (existente) de um array previamente alocado ou simplesmente usado e descartado.

  • Em nenhum caso, um novo armazenamento precisa ser alocado para conter uma referência ou um valor primitivo.

  • Normalmente, uma palavra de memória é tudo o que é necessário para armazenar uma referência de objeto ou array, e um valor primitivo normalmente ocupa uma ou duas palavras, dependendo da arquitetura do hardware.

  • Em nenhum caso o espaço precisa ser alocado pelo chamador para conter algum objeto / array retornado por um método. Em Java, objetos e matrizes são sempre retornados usando semântica de passagem por valor ... mas o valor que é retornado é um objeto ou referência de matriz.


Para obter mais informações, consulte estes recursos:

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.