Pílula de Java (#32): Duas coisas são infinitas: o universo e o sofrimento do GC com sua lista. Sobre o universo ainda temos dúvidas. Um dos memory leaks mais sutis em aplicações Java aparece em sistemas que acumulam eventos sem qualquer limite. A cada requisição, um objeto Evento é adicionado a uma ArrayList. Em desenvolvimento isso nunca falha, mas em produção, depois de semanas rodando, a aplicação passa a consumir gigabytes de heap até chegar ao inevitável OutOfMemoryError. A causa é direta: o Garbage Collector só remove objetos sem referências ativas. Quando você usa uma ArrayList como histórico permanente, cada evento permanece referenciado para sempre. Mesmo eventos antigos, que nunca mais serão lidos, continuam vivos na memória. E o problema se multiplica, se cada evento contém Usuário, Request ou Response, todos esses objetos também ficam retidos. Veja o impacto numérico real: 100 requisições por segundo = 8,6 milhões de eventos por dia, todos ocupando heap indefinidamente. Se cada evento tiver alguns kilobytes, isso rapidamente vira dezenas de gigabytes. O OutOfMemoryError se torna apenas uma questão de tempo. A bomba está plantada. A solução é simples e eficiente: use uma Queue com limite. Sempre que o tamanho exceder o máximo (por exemplo, 10 mil eventos), remova o mais antigo com poll(). Isso elimina a referência e permite que o GC faça seu trabalho. O sistema mantém apenas o histórico recente útil, sem comprometer a memória. Se você precisa manter eventos por tempo e não por quantidade, use limpeza periódica com @Scheduled (Spring Boot) ou ScheduledExecutorService. Outra abordagem ainda mais segura: não manter eventos em memória. Registre em log estruturado ou banco de dados e consulte quando necessário. O princípio é simples: nenhuma estrutura em memória deve crescer indefinidamente em aplicações de longa duração. Você já enfrentou esse tipo de leak? Como identificou e resolveu? #Java #BackendDevelopment #MemoryLeak #CleanCode #PerformanceEngineering
Sou java desde 1998 e nunca vi um out of memory
O problema é que muita gente tenta resolver tudo no código, quando a solução mais simples tá fora da aplicação. Guardar histórico infinito em memória não faz sentido se já existe storage pra isso. Se a ideia é salvar eventos, coloca num log, bucket, banco ou fila persistida. Além de evitar leak, você ainda ganha durabilidade e visibilidade do que tá rolando.
Eu faria uma alteração bem sutil. Em vez de: -adicionar o elemento -validar tamanho da lista -retirar se passar o tamanho Eu faria: -validar tamanho -adiciona somente se puder Você vai precisar validar de qualquer jeito, mas só vai processar a entrada do elemento se a validação for positiva
Muita gente pergunta: “Mas a lista não deveria ser static para causar leak?” A resposta é: não. Em frameworks como Spring Boot, Micronaut, Quarkus, etc., os beans por padrão têm escopo Singleton. Isso significa que o objeto é criado uma única vez e permanece vivo durante toda a vida da aplicação. Se esse bean contém uma lista interna, mesmo não sendo estática, essa lista também nunca é destruída, porque continua referenciada pelo singleton. Esse único detalhe já é suficiente para provocar um memory leak lógico: cada item adicionado permanece na memória para sempre, impedindo o Garbage Collector de liberar o espaço. O problema não é o static, mas sim a vida útil longa do objeto que mantém referências indefinidamente.
Uma dúvida: vale a pena transformar essa capacidade da fila em algo dinâmico? Ou melhor, adequando a minha pergunta para um cenário de infraestrutura: se eu estiver usando um pod ou um container e quiser passar como um parâmetro conforme a "demanda" do sistema aumenta e analogamente posso dispor de mais memória para aquele microserviço, essa ainda seria uma alternativa viável?
Parabéns pelo exemplo, muito bom lembra desses temas tão importantes mas esquecidos no dia a dia até virar problema em produção
Isso é muito útil e resolve alguns problemas. Estudando Rust achei muito interessante o drop em memória em coisas não utilizáveis. Sem GC
O tema de hoje sobre memory leaks está diretamente relacionado com uma outra pílula do passado: "HashMaps não esquecem jamais", onde falei sobre WeakHashMap como alternativa para resolver uma questão parecida. https://www.linkedin.com/posts/wandi_p%C3%ADlulas-de-java-hashmaps-n%C3%A3o-esquecem-jamais-activity-7374552111054807040-KiZk/