Olá Pessoal, tudo bom?
Após essa pausa para o assunto de for-each, vamos continuar a descrição sobre a Arquitetura da Java Virtual Machine, dentro do subsistema Runtime Data Area, vamos descrever hoje sobre a parte chamada Heap. Como você pode suspeitar essa área está relacionada com o armazenamento das instâncias de objetos criadas durante a execução da JVM. Lembrando que esse artigo continuará a utilizar alguns conceitos sobre arquitetura de sistemas operacionais, assim termos desconhecidos podem surgir no contexto desse artigo. Peço nesses casos que me envie comentários a respeito desses termos, para que eu possa complementar o artigo e responder suas duvidas.
Runtime Data Area
Relembrando…
No artigo sobre a Runtime Data Area, foi apresentada a Figura 01. Nessa figura foram exibidos alguns subsistemas existentes dentro dessa área.
Heap
A subárea conhecida como Heap é uma região com escopo temporário para realizar a alocação dinâmica e temporária de seus slots. Ela é criada durante a inicialização da JVM, sendo seus slots utilizados para armazenar instâncias de classes Java, sendo estes objetos não estáticos, criados durante a execução dos bytecodes gerados pelos aplicativos Java. Cada instância de JVM possui sua própria Heap, sendo essa única para a execução. Como consequência disso, todas as threads criadas por essa instância de JVM compartilham a mesma Heap.
Uma instância em execução da JVM não pode modificar a Heap da outra instância em execução da JVM. Isso não é verdadeiro para duas threads rodando dentro da mesma JVM, pois como compartilham uma única Heap, é possível que uma thread modifique informações da Heap, que podem ser sentidas por outras threads. Assim a sincronização do acesso as informações da Heap deve ser uma preocupação muito importante durante o desenvolvimento de um sistema.
Como nas outras subáreas, não existe uma padronização na forma dos desenvolvedores de JVMs criarem essa região, pois a especificação deixa aberto como deverá ser realizada essa implementação de acordo com cada Sistema Operacional. Todas as informações presentes na especificação podem possuir o valor necessário para estarem acomodadas com o SO, inclusive o tamanho inicial em bytes da Heap.
Assim como a subárea de Method Area, o tamanho da Heap pode aumentar ou diminuir conforme a execução da JVM. Na maioria das implementações da JVM o espaço em memória reservado para a subárea Method Area está localizado logo acima do espaço reservado para a Heap, facilitando assim a expansão/contração de ambas as subáreas. De qualquer forma a Heap possui um tamanho finito em bytes (De acordo com a memória existente no SO), assim o desenvolvedor Java pode especificar qual é o tamanho inicial da Heap, forçando assim o aumento do tamanho dessa Heap. Para estabelecer o tamanho inicial da Heap é necessário utilizar o argumento -Xms. Para estabelecer o tamanho máximo desta deve ser utilizado o argumento -Xmx. Mais detalhes aqui. Mesmo com essas alterações, caso a Heap ficar sem espaço em memória a JVM irá gerar a exceção OutOfMemoryError ou PermGemSpaceError.
A JVM possui várias formas de alocar memória dentro da Heap para a criação de novas instâncias, mas não existe nenhuma forma de liberar novamente esse espaço alocado dentro da Heap para a JVM novamente. Não é possível liberar a memória de um objeto diretamente no código Java. Essa tarefa é dada diretamente a JVM, que decide quando é possível liberar objetos que não estão mais sendo referenciados pela aplicação. Essa tarefa é representada dentro da JVM pela Garbage Collector, que realiza o gerenciamento da Heap.
Garbage Collection
Garbage Collection (GC), é um mecanismo primário que automaticamente libera a memória usada pelos objetos que não estão mais sendo referenciados pela JVM. Outra atividade realizada pelo GC é realizar movimentos dos espaços ocupados para reduzir a fragmentação da Heap.
Novamente não há uma única forma de implementar a funcionalidade de Garbage Collection. A especificação apenas obriga que a implementação gerencie sua própria heap de alguma maneira. Por exemplo, uma implementação pode simplesmente fixar o tamanho máximo que uma Heap pode ter e ao atingir essa marca, gerar uma OutOfMemoryException. Enquanto essa implementação não será uma das melhores para se trabalhar no dia a dia, ela está qualificada perante a especificação da JVM. Assim como a especificação não informa qual é o tamanho mínimo que é necessário para a JVM estar preparada para rodar programas. Por fim não está descrito na especificação a forma com que a JVM deverá liberar espaço em memória da Heap.
A especificação da JVM também não indica como o GC será implementado, mas como referências aos objetos que serão liberados da Heap podem estar em vários pontos da JVM, como Java Stacks, Heap, Method Area e Native Methods Stacks, a escolha da forma de implementar o GC deverá influenciar e muito, a definição de várias áreas da JVM.
Para facilitar o trabalho do Garbage Collection a subárea Heap é dividida em três regiões, conforme mostra a Figura 02:
- New Generation – Região onde novos objetos criados são armazenados.
- Old Generation ou Tenured Generation – Região onde objetos mais antigos são armazenados. Normalmente o GC move objetos da New Generation para a Old Generation após um certo tempo que o objeto esteja “vivo”.
- Perm Space – Região onde a JVM armazena metadados de classes e métodos.
Por fim existe ainda a forma de representar objetos dentro da Heap, mas isso fica como assunto para um outro artigo 🙂
finnaly{
Duvidas ou sugestões? Deixe seu feedback! Isso ajuda a saber a sua opinião sobre os artigos e melhorá-los para o futuro! Isso é muito importante!
Até um próximo post!
Leave a Reply