Um dos objetivos da JVM é gerenciar a memória utilizada pelos nossos sistemas. Isto é feito através de processos que são executados ao longo do ciclo de vida da aplicação. O garbage collector é um dos mais importantes. De forma resumida, ele é o responsável por liberar espaço na memória, coletando objetos que não estão mais sendo referenciados. A ideia deste post é explicar, em detalhes, como é feita esta coleta.
Garbage Collector
Sempre que instanciamos um objeto na nossa aplicação, o mesmo é alocado em um espaço de memória chamado heap. Com o passar do tempo muitos objetos perdem suas referências e não são mais úteis para o sistema. Com um acumulo de objetos não referenciados, o garbage collector é invocado. O processo é chamado de mark and sweep e envolve dois passos. No primeiro passo é necessário descobrir quais objetos ainda possuem referência. Uma vez descobertos estes objetos serão marcados. No segundo passo, todos os outros objetos que não foram marcados estarão prontos para a coleta e é nesse momento que ocorre uma varredura para liberação do espaço de memória. Um detalhe que não foi informado é que enquanto o processo é executado, a aplicação para de rodar, com o intuito de evitar concorrência com o garbage collector. Essa parada é chamada de stop the world. Se sempre que o garbage collector for varrer a heap, os objetos que possuem referência forem marcados, elevará o tempo da parada e os usuários sentirão que a aplicação não está respondendo naquele momento, o que não é interessante. Então como fazer para melhorar o processo de coleta?
Young e Old Generation
Para evitar o problema visto anteriormente, a heap foi dividida em gerações. Essas gerações são a young generation e a old generation. A young possui um espaço menor e é dividida em 3 partes, que são o eden, s0 e s1 (survivor espaces). Todo novo objeto será criado no eden. Conforme aumenta a quantidade de objetos no eden, o garbage collector é chamado, porém o processo de marcação e varredura leva menos tempo, pois conforme informado, há menos espaço destinado para a young generation. Após a execução do gc, os objetos que ainda possuem referência, serão alocados no espaço s0. Como novos objetos estão sendo criados no eden, quando o gc é executado, ele irá olhar para os sobreviventes do eden e do s0 e os migrará para o espaço s1. Após esse processo inicial, todos os objetos criados no eden, poderão ser migrados para o s0 ou s1, sem ordem de precedência e o gc atuará em todos estes espaços. Após um número x de execuções (a depender da JVM e configurações feitas pelos usuários) os objetos sobreviventes na young generation, serão fragmentados e movidos para a old generation. Na old generation o processo de coleta será executado apenas quando necessário, ou seja, quando não possuir mais espaço e isso ocorrerá com menor frequência.
Conclusão
Percebemos que o garbage collector é um processo extremamente importante para mantermos a performance da nossa aplicação. Porém, se fosse realizado a coleta em toda a heap, por existir o stop the world, a aplicação pararia de executar, para não concorrer com o gc e isso causaria uma instisfação aos usuários do sistema, que iriam sentir que a aplicação não estaria respondendo naquele momento. Isso é evitado graças as gerações da heap. Na young generation o processo de coleta é executado com maior frequência, mas de forma muito rápida, pois é um espaço menor, fazendo com que não seja percebida pelos usuários. Já na old generation, espaço que possui os objetos sobreviventes, o processo é executado apenas quando necessário, com uma frequência bem menor, e quando ocorre, apesar de ser sentido pelos usuários, não é tão prejudicial. O assunto do post de hoje foi curto, porém complexo, então toda crítica, dúvida ou sugestão serão bem-vindas. Espero que tenham gostado. Até o próximo.
Top comments (4)
Sempre aprendendo com seus posts mano!!! Valeu mesmo!!!
Eu que agradeço, Max!! Você é fera!! =)
Interessante, e é sempre bom saber como funciona os mecanismos internos, o que permite melhor otimizações e turning da configuração da JVM.
Que bom que gostou, Eduardo =)