Introdução
Antes de partirmos para a coleta de lixo das linguagens, vamos entender um pouco como um programa é alocado na memória.
Quem faz o intermédio entre o programa e o hardware é o sistema operacional, ele quem vai fazer a tradução dos endereços lógicos gerados pela compilação de um programa para o endereço físico em um bloco de memória do computador.
Esse bloco é particionado, armazenando informações estáticas, de tamanho fixo, e deixando espaço para alocação dinâmica. Vejamos na imagem a seguir:
Fixos
- CÓDIGO - temos o armazenamento da sequência de instruções em código de máquina.
- ESTÁTICO - aqui são guardadas as variáveis globais e estáticas, as quais precisam estar disponíveis durante toda execução do programa.
Dinâmicos
- HEAP - esse espaço é destinado à alocação das variáveis dinâmicas e instâncias de objetos.
- PILHA - na última partição são alocados os registros de ativação de uma função.
Nota-se que as duas últimas partições compartilham o mesmo espaço do bloco de memória.
A PILHA tem o início da sua alocação no final do bloco, crescendo de baixo para cima. Toda vez que uma função é concluída, ela é retirada do bloco automaticamente.
Enquanto o HEAP a alocação se dá no sentido oposto, desta forma o compartimento de alocação dinâmica é melhor aproveitado. É nesse particionamento que o coletor de lixo vai atuar.
Python
O python tem uma coleta de lixo automática, podem ser usadas duas estratégias:
Contagem de referência
Usada em versões anteriores a 2.0 do Python, baseada na contagem de vezes que um objeto é referenciado por outros objetos no sistema, onde a cada referência o contador é incrementado em +1 e quando a referência se perde, decrementamos -1. Quando o contador chega em zero, o objeto é desalocado.
Podem ocorrer referências cíclicas, onde os objetos não são atingidos de nenhuma maneira. Um modo fácil criar as referências cíclicas criando objetos que referenciam a si mesmos.
Coletor de lixo
Automático
O Python agenda a coleta de lixo automaticamente com base no seguinte cálculo: número de alocações - número de desalocações > número limite estabelecido.
Existe um módulo chamado gc que pode ser invocado para inspecionar esse limite.
gc.get_threshold()
Manual
Para os casos de referência cíclicas, o gc tem uma função que pode coletar o lixo de forma manual
gc.collect()
Java
O Java usa a estratégia de coleta de lixo parcial e total, funcionam da seguinte maneira:
O coletor de lixo é um processo automático, o qual examina a memória em busca de objetos que não estão sendo utilizados (sem referência do programa ao objeto) para fazer a exclusão dos mesmos.
O coletor é implementada na JVM e fica executando no background constantemente, podendo operar de duas maneiras:
- Menor ou Incremental
Ocorre quando os objetos de 'geração nova' são alocados na memória e em seguida perdem a referência, ao examinar a memória, eles serão removidos.
- Maior ou Total
Quando objetos sobrevivem à primeira coleta, esses são copiados para 'geração antiga ou permanente', estes são examinados com menos frequência.
Manual
Apesar da coleta de lixo ser automática, podemos tornar um objeto elegível para a remoção de forma manual, anulando o objeto (obj = null) ou criando objeto dentro de métodos, por exemplo. Também podemos solicitar à JVM a execução dos métodos gc para que remova esses objetos da memória mais rapidamente.
System.gc()
Conclusão
A diferença principal notada é que o gc do Python é executado se baseando em um cálculo para verificar se chegou ao valor limite. Já no Java o gc é executado na JVM, examinando os objetos constantemente, em paralelo com a execução do programa.