Início

topics

Coleta de lixo em Java

O que é coleta de lixo em Java?
Explore a solução de coleta de lixo em Java da IBM Inscreva-se para receber atualizações sobre IA
Ilustração com colagem de pictogramas de engrenagem, braço robótico, celular
O que é coleta de lixo em Java?

A coleta de lixo é uma funcionalidade fundamental da linguagem de programação Java que gerencia automaticamente a alocação e a desalocação de memória para objetos criados em um espaço éden.

A coleta de lixo em Java permite que os desenvolvedores se concentrem na programação sem se preocupar com o gerenciamento de memória, tornando o Java uma escolha popular para a criação de aplicações complexas e de grande escala. Entretanto, é essencial que os desenvolvedores Java entendam como a coleta de lixo funciona, para que possam otimizar o desempenho do código e evitar os erros comuns relacionados à memória. 

Neste guia, são explorados os fundamentos da coleta de lixo em Java, incluindo seus benefícios, diferentes tipos de coletores e as melhores práticas a serem seguidas durante a programação. Então, vamos nos aprofundar e explorar como funciona a coleta de lixo!

The Total Economic Impact da IBM Robotic Process Automation

Veja uma análise de custo e benefício do IBM Robotic Process Automation (RPA).

Conteúdo relacionado Leia o guia sobre observabilidade
O que são OutofMemoryErrors?

OutofMemoryError é um tipo de erro que ocorre quando um programa ou aplicação tenta alocar mais memória do que a quantidade disponível. Esse erro ocorre quando a Máquina Virtual Java (JVM) ou outra plataforma fica sem memória ao tentar executar uma aplicação.

Um OutofMemoryError geralmente ocorre quando uma aplicação ou programa tenta criar novos objetos, mas a JVM não consegue alocar memória para acomodá-los. Esse erro também pode ocorrer quando uma aplicação usa muita memória e não a libera corretamente.

Quando ocorre um OutofMemoryError, a aplicação geralmente trava e é encerrada. Esse erro é comum em programas que lidam com grandes volumes de metadados, como aplicações de processamento de imagem ou vídeo, ou programas que lidam com grandes bancos de dados.

Para resolver esse erro, pode ser necessário aumentar a quantidade de memória disponível para a aplicação ou otimizar o uso de memória dela. Para fazer, deve-se alterar os parâmetros da JVM ou usar uma ferramenta de criação de perfil de memória para identificar vazamentos ou uso ineficiente da memória.

Como funciona a coleta de lixo em Java?

Em Java, todos os objetos são armazenados no heap, que é uma parte da memória reservada para alocação dinâmica de objetos. Quando um objeto não é mais referenciado por nenhuma parte do programa, ele se torna qualificado para a coleta de lixo.

O coletor de lixo em Java verifica periodicamente a memória heap para encontrar objetos que não estejam em uso. O processo de coleta de lixo envolve várias etapas, incluindo marcação, varredura e compactação.

  • Marcação: a primeira etapa da coleta de lixo envolve a marcação de todos os objetos que ainda sejam referenciados pelo programa. Ela começa com um conjunto de objetos raiz, como variáveis globais, variáveis locais e parâmetros de método e, em seguida, rastreia todos os objetos acessíveis a partir dessas raízes. Os objetos que não podem ser acessados a partir das raízes são considerados qualificados para a coleta de lixo.

  • Varredura: após a fase de marcação, o coletor de lixo varre o heap Java para identificar e recuperar a memória que é usada pelos objetos que não estejam mais sendo referenciados. Isso envolve a desalocação da memória usada pelos objetos não utilizados e sua reinclusão no pool de memória livre.

  • Compactação: em alguns algoritmos de coleta de lixo, a fase de varredura é seguida por uma fase de compactação, na qual a memória usada pelos objetos restantes é reorganizada para minimizar a fragmentação. Isso envolve a aproximação de objetos e a criação de blocos contíguos maiores de memória livre.

A máquina virtual Java (JVM) executa automaticamente a coleta de lixo, para que o programador não precise gerenciar manualmente a memória. O coletor de lixo é executado em um thread separado e geralmente opera em segundo plano, para que não afete a execução normal do programa.

Tipos de coletores de lixo em Java

Existem dois tipos principais de algoritmos de coleta de lixo em Java: completa e incremental.

Coleta de lixo completa ou principal

A coleta de lixo completa é um processo no qual um coletor de lixo (uma parte do sistema de execução de uma linguagem de programação) pesquisa toda a memória usada por um programa e compila todos os objetos que não estejam mais sendo usados pelo programa. Assim, esses objetos são marcados como lixo e podem ser removidos da memória.

A coleta de lixo completa é geralmente realizada pelo sistema de execução de uma linguagem de programação que usa gerenciamento automático de memória, como Java ou Python. Durante o processo, o coletor de lixo suspende a execução do programa para realizar a pesquisa de objetos de lixo, o que pode causar uma desaceleração temporária no desempenho do programa.

A coleta de lixo completa geralmente é acionada quando a quantidade de memória usada por um programa atinge um determinado limite ou quando o programa solicita um novo bloco de memória e não há memória livre suficiente disponível. O objetivo da coleta de lixo completa é recuperar a memória que não é necessária para o programa, disponibilizando-a para uso por outras partes do programa ou por outros programas em execução na mesma máquina.

Coleta de lixo incremental ou secundária

A coleta de lixo incremental é um tipo de técnica de gerenciamento de memória usada por linguagens de programação e ambientes de execução para recuperar automaticamente a memória que não é mais necessária para um programa. Para fazer isso, ela identifica objetos na memória que não estejam em uso e libera a memória que eles ocupam para que possa ser reutilizada por outras partes do programa.

Na coleta de lixo incremental, o coletor de lixo examina periodicamente a memória do programa em busca de objetos inacessíveis na memória heap da nova geração. Em vez de interromper a execução do programa durante esse processo de verificação, o coletor de lixo divide a verificação em partes pequenas e gerenciáveis chamadas de “incrementos”. Durante cada incremento, o coletor de lixo examina uma parte da memória do programa, identificando os objetos que não são necessários e marcando-os como disponíveis para reutilização.

Ao usar incrementos, o coletor de lixo pode recuperar a memória em pequenos pedaços, sem interromper a execução do programa por um período prolongado. Isso ajuda manter o programa responsivo e evita que ele sofra pausas ou atrasos significativos em consequência do processo de coleta de lixo.

Entretanto, a coleta de lixo incremental pode ser menos eficiente do que outros tipos de técnicas de coleta de lixo, como “marcação e varredura” ou coleta de lixo geracional, pois exige verificações mais frequentes da memória do programa. Além disso, o uso de incrementos pode introduzir certa sobrecarga na execução do programa, pois o coletor de lixo precisa manter as informações de estado entre cada incremento.

Benefícios da coleta de lixo em Java

No geral, a coleta de lixo do Java traz muitos benefícios que fazem dele uma ferramenta valiosa para os desenvolvedores. Veja alguns benefícios do uso da coleta de lixo do Java:

  1. Não há gerenciamento manual da memória
  2. Impede vazamentos de memória
  3. Alocação dinâmica de memória
  4. Melhor desempenho
  5. Otimização de memória
  • Não há gerenciamento manual da memória: com a coleta de lixo, os desenvolvedores não precisam gerenciar manualmente a alocação e a desalocação de memória. Isso significa que os programadores podem se concentrar mais em programar e menos em gerenciar a memória, o que ajuda a reduzir os erros e aumentar a produtividade.

  • Evita vazamentos de memória: a coleta de lixo evita vazamentos de memória, que podem ocorrer quando um programa não libera a memória que não é mais necessária. Isso pode fazer com que o programa consuma mais memória do que o necessário, causando lentidão no desempenho e, por fim, travamento.

  • Alocação dinâmica de memória: a coleta de lixo do Java permite a alocação dinâmica da memória, o que significa que a memória é alocada conforme necessário no tempo de execução. Isso evita erros de alocação de memória e pode deixar o programa mais eficiente.

  • Melhor desempenho: a coleta de lixo ajuda a melhorar o desempenho de um programa, reduzindo o tempo gasto no gerenciamento da memória. Isso pode levar a tempos de execução menores e a um programa mais responsivo.

  • Otimização de memória: a coleta de lixo pode otimizar o uso da memória reutilizando a memória que não é usada por uma parte do programa para outras partes dele. Isso ajuda a reduzir o uso da memória e melhora a eficiência geral do programa.

Os desenvolvedores se beneficiam da capacidade da coleta de lixo Java de gerenciar automaticamente a memória, evitar vazamentos, permitir a alocação dinâmica, melhorar o desempenho e otimizar seu uso. A coleta de lixo ajuda os desenvolvedores a criar programas melhores e mais eficientes.

Quais eventos acionam a coleta de lixo do Java?

No Java, a coleta de lixo é acionada automaticamente pela JVM (Máquina Virtual Java) quando determina que o heap está ficando cheio ou após um determinado tempo ter passado.

Há vários eventos que podem acionar a coleta de lixo no Java:

  • Alocação de espaço heap: quando a JVM precisa alocar memória para um novo objeto e não há espaço suficiente no heap, ela aciona a coleta de lixo para recuperar a memória não utilizada ou armazená-la no espaço de sobrevivência.

  • Solicitação do método System.gc(): é possível solicitar explicitamente a coleta de lixo pelo método System.gc(), embora não haja garantia de que ela será executada.

  • Limite da geração antiga: a coleta de lixo também pode ser acionada quando o tamanho do espaço heap da geração antiga (que armazena objetos de longa duração) atinge um determinado limite.

  • Limite de PermGen/Metaspace: nas versões anteriores ao Java 8, a coleta de lixo também pode ser acionada quando o tamanho das áreas de memória PermGen (geração permanente) ou Metaspace (no Java 8 e posteriores) atinge um determinado limite.

  • Com base no tempo: às vezes, a coleta de lixo pode ser acionada com base em um intervalo de tempo. Por exemplo, a JVM pode acionar a coleta de lixo a cada hora ou todos os dias, independentemente do uso de memória.

Vale a pena observar que o comportamento exato da coleta de lixo no Java pode variar dependendo da implementação e da configuração da JVM.

Como solicitar que a JVM execute o coletor de lixo

Para solicitar que a Máquina Virtual Java (JVM) execute o coletor de lixo, você pode seguir estas etapas:

  1. Solicite o método System.gc(): esse método é usado para solicitar que a JVM execute o coletor de lixo. Não há garantia de que o coletor de lixo será executado imediatamente após a solicitação desse método.

  2. Use o método Runtime.getRuntime().gc(): esse método é semelhante ao System.gc(), mas é menos provável que seja substituído pela implementação da JVM.
  3. Use o sinalizador JVM -XX:+DisableExplicitGC: esse sinalizador desativa as solicitações explícitas de coleta de lixo. Isso significa que, mesmo que você solicite o System.gc() ou Runtime.getRuntime().gc(), o coletor de lixo não será acionado.

É importante observar que geralmente não é recomendável solicitar explicitamente o coletor de lixo para execução, pois a JVM é projetada para gerenciar automaticamente a alocação de memória e a coleta de lixo. Às vezes, as solicitações explícitas de coleta de lixo podem prejudicar o desempenho. 

Quando um objeto é qualificado para coleta de lixo?

Um objeto em uma linguagem de programação é qualificado para coleta de lixo quando não é mais referenciado por nenhuma parte do programa. A coleta automática de lixo é um processo executado pelo ambiente de execução da linguagem de programação para recuperar a memória.

Na maioria das linguagens de programação modernas, a coleta de lixo é feita automaticamente pelo ambiente de tempo de execução. Os algoritmos específicos usados para coleta de lixo podem variar dependendo da linguagem de programação e da implementação. Porém, o princípio geral é o mesmo: o ambiente de execução verifica periodicamente o heap (a parte da memória que é usada para objetos alocados dinamicamente) para identificar objetos que não podem mais ser acessados por nenhum objeto ativo no programa. Quando um objeto é identificado como inacessível, ele é marcado como lixo e sua memória pode ser recuperada.

O tempo exato em que um objeto fica qualificado para coleta de lixo depende do algoritmo de coleta de lixo específico usado pelo ambiente de execução. Alguns algoritmos são mais agressivos que outros e podem recuperar a memória mais rápido, enquanto outros podem atrasar a coleta de lixo para otimizar o desempenho. Contudo, em geral o programador não precisa se preocupar em gerenciar a memória manualmente, já que o ambiente de execução cuida disso automaticamente.

Quais coletores de lixo estão disponíveis para Java?

Há vários coletores de lixo para Java, incluindo:

  1. Coletor de lixo em série
  2. Coletor de lixo paralelo
  3. Coletor de varredura de marcação simultânea (CMS)
  4. Coletor de lixo G1
  • Coletor de lixo em série: é o coletor de lixo padrão do Java e é normalmente usado em aplicações de pequeno e médio porte que não exigem alta produtividade. Esse tipo de coletor ajuda a evitar a ocorrência dos eventos comuns de “fazer o mundo parar”.

  • Coletor de lixo paralelo: foi projetado para aplicações de alta produtividade e é particularmente útil em aplicações que exigem grandes heaps, pois utiliza várias CPUs para acelerar o processo. É importante observar que esse tipo de coletor congela os threads da aplicação quando executado.

  • Coletor de varredura de marcação simultânea (CMS): o coletor CMS foi projetado para aplicações que exigem períodos de pausa menores e é útil em aplicações com muitos objetos ativos.

  • Coletor de lixo G1: foi projetado para grandes heaps e pode lidar com uma combinação de objetos de vida curta e longa. Ele usa vários threads para verificar e compactar o heap simultaneamente.

Cada coletor de lixo tem suas próprias vantagens e desvantagens. Assim, a escolha do coletor depende das necessidades específicas da aplicação. Também é possível configurar e ajustar as configurações do coletor de lixo para otimizar o desempenho de uma aplicação específica.

Qual é a diferença entre coleta de lixo e vazamento de memória?

A coleta de lixo e os vazamentos de memória estão ambos relacionados ao gerenciamento de memória em programas de computador, mas têm significados e implicações distintos.

Como já mencionado, a coleta de lixo é geralmente executada pela linguagem de programação ou pelo ambiente de execução e evita que os programas consumam mais memória do que o necessário. A coleta de lixo identifica a memória que está livre para ser usada por outras partes do programa ou por outros programas em execução no computador.

Por outro lado, um vazamento de memória ocorre quando um programa não consegue liberar a memória que alocou, mesmo quando essa memória não é mais necessária. Consequentemente, o programa continua consumindo memória ao longo do tempo, levando ao eventual esgotamento da memória disponível, o que pode levar ao travamento do programa ou de todo o sistema operacional. Os vazamentos de memória geralmente são causados por bugs no programa e podem ser difíceis de identificar e corrigir.

Em resumo, a coleta de lixo é um processo para liberar automaticamente a memória que não é mais necessária. Já os vazamentos de memória ocorrem quando a memória é alocada, mas não liberada por um programa, causando um acúmulo gradual de seu uso.

O Instana ajuda você a monitorar o desempenho das aplicações Java

Concluindo, a coleta de lixo é um aspecto essencial da programação em Java que garante o gerenciamento eficiente da memória ao recuperar a memória não utilizada. A observabilidade do Instana fornece ferramentas avançadas para os desenvolvedores monitorarem e otimizarem o processo de coleta de lixo em tempo real. 

Ao usarem o Instana, os desenvolvedores podem identificar com rapidez vazamentos de memória, otimizar as configurações da coleta de lixo e resolver problemas de desempenho relacionados a esse processo.

Com os recursos abrangentes de monitoramento do Instana, os desenvolvedores podem extrair insights profundos sobre o uso da memória e o comportamento da coleta de lixo de suas aplicações Java, permitindo que eles forneçam softwares confiáveis e de alto desempenho. 

Seguindo as melhores práticas descritas neste guia, os desenvolvedores podem usar o Instana para otimizar o processo de coleta de lixo e melhorar o desempenho geral de suas aplicações Java. Com a observabilidade do Instana, os desenvolvedores se antecipam a qualquer problema que possa surgir, garantindo que as aplicações tenham sempre o melhor desempenho possível.

Produtos relacionados
IBM Instana Observability

Aumente a funcionalidade e a observabilidade no seu APM empresarial; aprimore o gerenciamento de desempenho das aplicações e acelere os pipelines de CI/CD, independentemente de onde as aplicações estejam localizadas.

Conheça o IBM Instana Observability

Recursos O que é observabilidade?

A observabilidade oferece visibilidade profunda dos aplicativos distribuídos modernos para identificação e resolução de problemas mais rápidas e automáticas.

O que é Java?

Saiba por que o Java continua sendo uma plataforma de desenvolvimento tão popular e como ele acelera projetos e oferece suporte a uma ampla gama de tecnologias emergentes.

O que é desenvolvimento de software?

Entenda os princípios essenciais do desenvolvimento de software e como isso impulsiona a inovação e a competitividade das empresas.

O que é o ambiente de execução Java (JRE)?

Saiba o que o ambiente de execução Java (JRE) faz e como ele funciona com outros componentes dessa plataforma para executar aplicações Java.

O que é gerenciamento de desempenho de aplicações (APM)?

Preveja e evite problemas de desempenho antes que eles afetem seus negócios com o gerenciamento de desempenho de aplicações.

O que é engenharia de confiabilidade local (SRE)?

Automatize tarefas de operações de TI, acelere a entrega de software e minimize os riscos de TI com engenharia de confiabilidade local.

Dê o próximo passo

O IBM Instana fornece observabilidade em tempo real que todos e qualquer um podem usar. Ele proporciona um rápido time to value enquanto verifica se sua estratégia de observabilidade pode acompanhar a complexidade dinâmica dos ambientes atuais e futuros. Do celular ao mainframe, o Instana é compatível com mais de 250 tecnologias e está crescendo. 

Explore o IBM Instana Agende uma demonstração em tempo real