Como convencer o Java Garbage Collector para executar quando o trabalho conjunto é pequeno?

Este é ainda outro "por favor me diga como forçar o coletor de lixo Java para executar" questão. Em nossa aplicação, acredito que temos boas razões para fazer isso.

Este é um aplicativo de servidor, que normalmente tem cerca de 5 milhões de objetos ativos. Uma vez a cada 5 minutos, realizamos uma tarefa de análise que leva cerca de 60 segundos. Se um GC completo for disparado enquanto a análise estiver em execução, haverá cerca de 40 milhões de objetos ativos. Os objetos extra de 35M se tornam lixo quando a análise é concluída. O servidor deve permanecer responsivo às solicitações em todos os momentos (mesmo enquanto a análise estiver sendo executada).

Descobrimos que um GC completo leva cerca de 1,5 segundo se invocado quando a análise não está em execução, mas em torno de 15 segundos enquanto a análise está sendo executada. Infelizmente, nosso padrão de alocação é tal que os GC completos geralmente são acionados durante a análise, mesmo que a análise esteja ocorrendo apenas 20% do tempo. (Cada terceira ou quarta análise executa um GC completo.)

Eu adicionei código para chamar o muito desprezado System.gc () antes de iniciar uma execução de análise, se o espaço livre na geração anterior estiver abaixo de um certo limite (5 GB). O benefício foi muito substancial: estamos recebendo 1,5 segundos de pausa em vez de 15 segundos de pausa e liberamos mais lixo no negócio. No entanto, às vezes, a chamada System.gc () é ignorada e acabamos com uma pausa de 15 segundos alguns minutos depois, quando o GC é disparado automaticamente.

Minha pergunta, então: há algo que podemos fazer para convencer mais fortemente o coletor de lixo a ser executado? Estamos executando o 1.7.0_09-icedtea e usando o GC Paralelo. Eu gostaria de (a) uma maneira confiável de forçar manualmente a coleta de lixo, ou (b) alguma maneira de ajustar o coletor para que ele tome uma decisão automática mais inteligente. (b) parece difícil, pois não está claro para mim como o colecionador poderia detectar que o nosso conjunto de trabalho varia dessa maneira dramática.

Estou disposto a recorrer a hackeamentos substanciais, se necessário; Este é um problema sério para nós. (Podemos examinar os compactadores CMS ou G1 como alternativas, mas desconfio do impacto da taxa de transferência do CMS, e o G1 tem a reputação de se comportar mal em face dos grandes arrays de bytes, que usamos.)

termo aditivo: Na produção, nossa experiência até agora tem sido que System.gc ()usualmente dispara uma coleta de lixo completa; pelo menos, nas situações em que estamos chamando. (Apenas o chamamos uma vez a cada 10 a 30 minutos, com o heap um pouco, mas não completamente preenchido com lixo.) Seria bom poder acionar a coleta de lixo com mais segurança, mas isso está nos ajudando a maior parte do tempo.

questionAnswers(4)

yourAnswerToTheQuestion