Para otimizar o desempenho do coletor de lixo, o heap gerenciado está dividido em três gerações: 0, 1 e 2.
Algoritmo de coleta de lixo do runtime baseia-se em várias generalizações que descobriu a indústria de software de computador para serem verdadeiras por experiências com esquemas de coleta de lixo. Primeiro, é mais rápido compactar a memória para uma parte do heap gerenciado que para o heap gerenciado inteiro. Em segundo lugar, objetos mais recentes terão vidas úteis menores e objetos mais antigos objetos terão vidas úteis maiores. Finalmente, objetos mais recentes tendem a ser relacionados entre si e acessados pelo aplicativo aproximadamente ao mesmo tempo.
O coletor de lixo do Runtime armazena novos objetos na geração 0.
Objetos criados com antecedência no tempo de vida do aplicativo que sobrevivem a coletas são promovidos e armazenados em gerações 1 e 2. O processo de promoção do objeto é descrito posteriormente neste tópico. Porque é mais rápido compactar uma parte da heap gerenciada que a heap inteira, este esquema permite que o coletor de lixo libere a memória em uma geração específica em vez liberar a memória para toda a memória gerenciada a cada vez que ele executa uma coleta.
Na verdade, o coletor de lixo executa uma coleta quando a geração 0 está cheia.
Se um aplicativo tentar criar um novo objeto quando a geração 0 está cheia, o coletor de lixo descobre que não existe nenhum espaço de endereço restante na geração 0 para alocar para o objeto. O coletor de lixo executa uma coleta em uma tentativa de liberar espaço de endereço na geração 0 para o objeto. O coletor de lixo inicia examinando os objetos na geração 0 em vez de todos os objetos na heap gerenciada. Isso é a abordagem mais eficiente, porque novos objetos costumam ter tempos de vida curtos, e é esperado que muitos dos objetos na geração 0 não estejam mais em uso mais pelo aplicativo quando uma coleta é executada. Além disso, uma única coleta de geração 0 frequentemente recupera memória suficiente para permitir ao aplicativo continuar criando novos objetos.
Após o coletor de lixo executar uma coleta de geração 0, ele compacta a memória para os objetos acessíveis conforme explicado anteriormente neste tópico em Liberando memória.
O coletor de lixo então promove esses objetos e considera esta parte da heap gerenciada como geração 1. Pelo fato de que objetos que sobrevivem a coletas costumam ter vidas úteis mais longas, faz sentido promovê-los para uma geração superior. Como resultado, o coletor de lixo não tem que reexaminar os objetos em gerações 1 e 2 sempre que ele executa uma coleta de geração 0.
Após o coletor de lixo executar sua primeira coleta de geração 0 e promover os objetos acessíveis na geração 1, ele considera o resto da heap gerenciada como geração 0.
Ele continua a alocar memória para novos objetos na geração 0 até que a geração 0 esteja cheia e que seja necessário executar outra coleta. Nesse ponto, o mecanismo de otimização do coletor de lixo determina se ele é necessário examinar os objetos em gerações mais antigas. Por exemplo, se uma coleta de geração 0 não recupera memória suficiente para o aplicativo concluir sua tentativa de criar um novo objeto de forma bem sucedida, o coletor de lixo pode executar uma coleta de geração 1, e depois de geração 2. Se isso não recuperar memória suficiente, o coletor de lixo pode executar uma coleta de gerações 2, 1, e 0. Após cada coleta, o coletor de lixo compacta os objetos acessíveis na geração 0 e promove-os para geração 1. Objetos na geração 1 que sobrevivem a coletas são elevados para geração 2. Como o coletor de lixo oferece suporte somente a três gerações, objetos na geração 2 que sobrevivem a uma coleta permanecem na geração 2 até que eles sejam determinados como inalcançáveis em uma coleta futura.