Pular para o conteúdo principal

Vazamento de memória: Causas, detecção e como corrigi-lo

Descubra o que causa vazamentos de memória, exemplos do mundo real, métodos de detecção e práticas recomendadas para evitar problemas de desempenho.
Actualizado 25 de fev. de 2025  · 15 min de leitura

Todo programa que executamos, grande ou pequeno, requer memória para ser processado. No entanto, quando um programa usa a memória e não a libera após o uso, isso leva a um vazamento de memória. 

Com o tempo, mais vazamentos de memória podem resultar em falta de armazenamento e falha no processamento das próximas tarefas. É por isso que detectar e gerenciar vazamentos de memória é fundamental para evitar erros desnecessários.

Neste artigo, exploraremos os vazamentos de memória em profundidade. Vamos começar!

O que é um vazamento de memória?

Os vazamentos de memória ocorrem quando um programa ou aplicativo utiliza a memória e não a libera após o uso. Por memória, quero dizer RAM - não a confunda com a memória do disco rígido.  Esses vazamentos se acumulam gradualmente, deixando a RAM cheia demais para lidar com novos processos. 

Os vazamentos de memória esgotam a RAM e afetam o desempenho, aumentando as operações de E/S. À medida que os vazamentos de memória se acumulam, o sistema tenta liberar a RAM transferindo os dados para o disco, o que leva a um aumento nas operações de E/S do disco.

A segurança também está em risco quando vazamentos de memória bloqueiam dados confidenciais. Se informações como senhas ou chaves de criptografia permanecerem na RAM por mais tempo do que o necessário, elas ficarão mais vulneráveis a invasores.

Exemplos de vazamentos de memória em linguagens de programação populares

Para entender melhor como ocorrem os vazamentos de memória, nada melhor do que vê-los em ação com alguns exemplos. 

Vazamentos de memória em Python

O Python se baseia na contagem de referências para o gerenciamento de memória. Ele remove um objeto quando sua contagem de referência - o número de outros objetos que se referem a ele - cai para zero. No entanto, ele tem algumas limitações, como o fato de osite não lidar com referências circulares.

Para quem não está familiarizado com o termo, uma referência circular ocorre quando duas ou mais variáveis se referem umas às outras de forma circular. 

Por exemplo, o objeto a se refere a b, b se refere a c e c se refere novamente a a, que é um loop infinito. Aqui, a contagem de referências nunca pode chegar a 0, e os objetos permanecem na memória para sempre, o que leva a vazamentos de memória no Python.

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None 

# Create two nodes
node1 = Node(1)
node2 = Node(2)

# Establish a circular reference
node1.next = node2  # node1 refers to node2
node2.next = node1  # node2 refers back to node1

O trecho de código acima mostra uma referência circular. O Python tem um coletor de lixo para lidar com essa cenarios. Ainda assim, se ele não conseguir lidar com cenários específicos, como ao usar variáveis globais, você deverá gerenciar manualmente os vazamentos de memória definindo as referências de objetos que não estão mais em uso como None.

Recomendo que você aprenda a escrever classes com eficiência de memória em Python para acelerar o tempo de execução e, ao mesmo tempo, consumir menos recursos.

Vazamentos de memória em Java

O Java gerencia automaticamente a memória e não requer ajuda explícita dos programadores. No entanto, em casos como registros indevidos de ouvintes ou referências estáticas, o coletor de lixo pode não conseguir liberar o espaço, levando a vazamentos de memória. Vamos ver como isso pode acontecer:

  • Uma fonte de eventos gera eventos, e um objeto ouvinte se registra para ser notificado quando esses eventos ocorrerem. 
  • Se a origem do evento mantiver uma referência forte ao ouvinte, o ouvinte não poderá ser coletado pelo lixo enquanto a origem do evento estiver ativa, mesmo que o ouvinte não esteja mais em uso. 

Nesses casos, podem ocorrer vazamentos de memória. Para evitá-los, cancele manualmente o registro dos ouvintes quando eles não forem mais necessários.

Outra causa comum de vazamento de memória são as variáveis estáticas. As variáveis estáticas são armazenadas na memória durante todo o ciclo de vida. Portanto, se eles fizerem referência a objetos, esses objetos não serão coletados pelo lixo, mesmo que não estejam mais em uso, causando vazamentos de memória. Por exemplo:

import java.util.ArrayList;
import java.util.List;

public class StaticMemoryLeak {

    // Static list
    private static List<Object> staticList = new ArrayList<>();

    public static void addObject(Object obj) {
        // Add the object to the static list
        staticList.add(obj);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            Object obj = new byte[1024 * 1024];
            // Add the object to the static list
            addObject(obj);
        }
    }
}

No programa acima, a variável staticList é declarada como uma matriz estática, e os objetos são adicionados a ela. O loop é executado 1.000 vezes, adicionando 1 MB de objetos a cada vez, resultando em 1 GB de memória total. 

Como a lista é estática, ela nunca perderá referências aos objetos enquanto o programa estiver ativo. Portanto, o coletor de lixo não pode excluir esses objetos e 1 GB de memória será mantido durante todo o ciclo de vida. Essa memória de objeto não utilizada pode causar erros no site OutOfMemoryError. Para corrigir isso, você deve chamar explicitamente staticList.clear() e liberar a memória.

Vazamentos de memória em C/C++

Diferentemente de Java e Python, o C++ não contém coletores de lixo automáticos. Portanto, os vazamentos de memória em C++ ocorrem quando os programadores alocam memória e se esquecem de desalocá-la. Por exemplo, 

void sample_leak() { 
    int* ptr = new int(5);
    return; 
}

No trecho acima, o ponteiro contém o endereço de memória onde o número inteiro 5 está armazenado. Quando a função termina, a variável local ptr sai do escopo, mas a memória alocada no heap permanece, causando um vazamento de memória. 

Para evitar isso, adicione explicitamente a linha delete ptr; para desalocar a memória.

Vazamentos de memória em JavaScript

O Javascript tem um coletor de lixo que gerencia automaticamente a memória. Ele funciona nas seguintes etapas: encontrar a raiz, seguir recursivamente seu caminho para os filhos e marcar cada filho como ativo ou inativo. Por fim, exclua todas as referências inativas. 

No entanto, o coletor de lixo pode não liberar a memória nos seguintes casos:

  1. Variáveis globais: Quando você se esquece de declarar uma variável com let, var ou const, o Javascript a cria automaticamente como uma variável global. Enquanto o programa for executado, as variáveis globais permanecerão na memória e estarão sempre acessíveis, impedindo que o coletor de lixo as libere. 
  2. setTimeOut(): O setTimeOut() agenda uma função de retorno de chamada para ser executada após um determinado tempo. Pode ocorrer um vazamento de memória quando essa função de retorno de chamada mantém a referência por mais tempo. Aqui está um exemplo:
function TimeoutExample() {
  var obj = 10; 
  setTimeout(function() {
    console.log(obj); 
  }, 1000);  // This runs after 1 second
}

TimeoutExample();

No código acima, mesmo após o término da função TimeoutExample(), o obj ainda mantém uma referência até que a função de retorno de chamada seja executada, pois o obj é utilizado dentro da função de retorno de chamada. Se isso acontecer com objetos grandes, você terá sérios vazamentos de memória. 

Causas de vazamentos de memória

Conforme mencionado, os vazamentos de memória podem ocorrer em várias linguagens de programação por diferentes motivos. Algumas linguagens não têm coleta automática de lixo, enquanto outras podem deixar de liberar memória em cenários anômalos. 

Vamos examinar detalhadamente alguns motivos comuns:

  • Referências inéditas: Sempre que criamos objetos ou variáveis, o sistema aloca memória ou referências para eles. Se você não fechar essas referências após o uso, poderá bloquear a memória. Esse tipo de memória se acumula com o tempo e leva a problemas de memória. 
  • Referências circulares: As referências circulares ocorrem quando vários objetos fazem referência uns aos outros, formando um loop. Mesmo que os objetos não estejam mais em uso, eles permanecem referenciados por outros objetos no ciclo, impedindo que o coletor de lixo recupere a memória.
  • Gerenciamento inadequado de recursos: Às vezes, não fazemos um esforço extra para fechar adequadamente as conexões de banco de dados, os soquetes de rede ou os manipuladores de arquivos após o uso. Essa ignorância pode levar a sérios problemas de vazamento de memória. Por exemplo, o sistema operacional tem descritores de arquivos limitados para lidar com arquivos abertos. Se os arquivos nunca forem fechados, o sistema operacional ficará sem descritores de arquivos, impedindo que o sistema abra novos arquivos.
  • Uso indevido de variáveis estáticas: Os vazamentos de memória geralmente ocorrem devido ao uso excessivo de variáveis estáticas. Como as variáveis estáticas permanecem ativas durante todo o tempo de vida do programa, todos os objetos a que elas fazem referência permanecem na memória, mesmo quando não estão em uso. Para evitar vazamentos de memória, esses objetos devem ser liberados explicitamente ou evitar o uso de variáveis estáticas.
  • Bibliotecas e estruturas externas: As bibliotecas de terceiros e as estruturas externas também podem introduzir vazamentos de memória devido ao gerenciamento ineficiente de recursos. Os vazamentos de memória ocorrem quando eles utilizam os recursos do sistema e não os liberam. 

Como detectar vazamentos de memória?

Agora que examinamos por que os vazamentos de memória podem ocorrer, discutiremos alguns métodos de detecção confiáveis para identificá-los e depurá-los.

  • Inspeção manual: Revise cuidadosamente o código para identificar possíveis causas de vazamentos de memória, como referências circulares, variáveis estáticas, instruções de desalocação ausentes ou variáveis que contêm referências a objetos não utilizados.  Ao inspecionar minuciosamente esses padrões no código, você pode identificar o problema exato e resolvê-lo de forma proativa. 
  • Usando ferramentas de depuração: Existem várias ferramentas de depuração e bibliotecas nativas de diferentes linguagens de programação para detectar vazamentos de memória. Por exemplo, o tracemalloc do python nos permite comparar instantâneos de memória em diferentes pontos no tempo e monitorar as alocações de memória entre esses períodos.  Além disso, o criador de perfil de memória do Python nos permitedepurar cada linha de código e identificar áreas com uso excessivo e inesperado de memória.
  • Monitoramento do uso da memória: As ferramentas de monitoramento de memória monitoram proativamente o consumo de memória e identificam problemas em tempo real. Essas ferramentas alertam você sobre problemas críticos de memória e fornecem logs relevantes, juntamente com sugestões de como corrigi-los. Os exemplos incluem Valgrind, Paessler, AddressSanitizer e outros. 
  • Escrever testes para vazamentos: Considere adicionar testes de unidade que detectem vazamentos de memória. Dessa forma, além dos problemas de funcionalidade e desempenho, os vazamentos de memória são detectados durante o desenvolvimento. 
  • Escrevendo testes de integração: Os testes de integração também devem ser usados para simular cenários do mundo real e detectar possíveis vazamentos de memória que possam surgir na produção.

Práticas recomendadas para evitar vazamentos de memória

Os vazamentos de memória são comuns em aplicativos que dependem de recursos de memória. Aqui estão algumas práticas que você pode seguir para evitá-los. 

Gerenciamento eficiente de recursos

Tente usar linguagenscomo Java ou Python quetratam automaticamente a memória usando coletores de lixo. Caso contrário, em linguagens como C ou C++, certifique-se de que toda a memória alocada seja explicitamente excluída. 

Além disso, use construções como blocos finally ou gerenciadores de contexto, como with em Python ou try-with-resources em Java, para uma limpeza eficiente dos recursos. Essas práticas ajudam a evitar vazamentos de memória e a garantir o gerenciamento adequado dos recursos. 

Use referências fracas

Ao contrário das referências fortes, as referências fracas não impedem que os objetos sejam coletados pelo lixo. Mesmo que eles mantenham referências aos objetos, eles não levam em conta a acessibilidade do objeto. Assim, o coletor de lixo pode recuperar a memória associada a esse objeto. Portanto, use referências fracas em vez de fortes. 

Revisões frequentes de código

É importante realizar revisões regulares do código para identificar vazamentos de memória. Ao analisar o código, procure padrões comuns, como recursos não fechados, referências circulares, variáveis globais ou estáticas e cache ineficiente. Dessa forma, você encontrará rapidamente o problema antes que ele afete seu sistema. 

Conclusão

Neste artigo, exploramos os principais aspectos dos vazamentos de memória, desde suas causas e exemplos até as técnicas de detecção. Vimos como diferentes cenários podem levar a vazamentos de memória e como você pode lidar com eles. Além disso, discutimos as práticas recomendadas que você deve seguir para evitar vazamentos de memória no futuro.  

Como exploramos os vazamentos de memória em diferentes linguagens de programação, recomendo que você explore os cursos a seguir para aprofundar seu conhecimento:

Torne-se um desenvolvedor Python

Adquira as habilidades de programação de que todos os desenvolvedores de Python precisam.
Comece a aprender de graça

Perguntas frequentes

Quais são os sinais comuns de um vazamento de memória?

Alguns sintomas comuns indicam que os vazamentos de memória afetam o sistema: lentidão do sistema, lentidão do navegador, dos aplicativos ou falhas no sistema operacional. 

Quais linguagens são mais propensas a vazamentos de memória?

Linguagens como C e C++ são propensas a vazamentos de memória porque não têm coletores de lixo que tratam automaticamente a memória. Em vez disso, você deve alocar e desalocar manualmente a memória.

Você pode ter vazamentos de memória em linguagens de programação modernas?

Sim! A coleta automática de lixo nas linguagens de programação modernas não consegue lidar com cenários como registros inadequados de ouvintes de eventos e variáveis estáticas ou globais.

Como faço para corrigir um vazamento de memória?

Para corrigir um vazamento de memória, siga estas etapas:

  • Identificar o vazamento usando ferramentas de perfil.
  • Analise a causaSe você tiver uma causa, poderá encontrar um problema, como alças de arquivo não fechadas ou referências persistentes.
  • Liberar memória explicitamente em linguagens como C/C++ ou gerenciar referências adequadamente em linguagens com coleta de lixo.
  • Otimize o gerenciamento de memória usando as práticas recomendadas, como referências fracas e tratamento adequado do ciclo de vida do objeto.

Srujana Maddula's photo
Author
Srujana Maddula
LinkedIn

Srujana é redatora freelancer de tecnologia e tem um diploma de quatro anos em Ciência da Computação. Escrever sobre vários tópicos, incluindo ciência de dados, computação em nuvem, desenvolvimento, programação, segurança e muitos outros, é algo natural para ela. Ela gosta de literatura clássica e de explorar novos destinos.

Temas

Saiba mais sobre programação com estes cursos!

Certificação disponível

curso

Python intermediário

4 hr
1.2M
Eleve o nível de suas habilidades em ciência de dados criando visualizações usando Matplotlib e manipulando DataFrames com pandas.
Ver DetalhesRight Arrow
Iniciar curso
Ver maisRight Arrow
Relacionado
Data Skills

blog

6 práticas recomendadas de Python para um código melhor

Descubra as práticas recomendadas de codificação Python para escrever os melhores scripts Python da categoria.
Javier Canales Luna's photo

Javier Canales Luna

13 min

blog

A maldição da dimensionalidade no aprendizado de máquina: Desafios, impactos e soluções

Explore a maldição da dimensionalidade na análise de dados e no aprendizado de máquina, incluindo seus desafios, efeitos nos algoritmos e técnicas como PCA, LDA e t-SNE para combatê-la.
Abid Ali Awan's photo

Abid Ali Awan

7 min

tutorial

Entendendo o desvio de dados e o desvio de modelo: Detecção de deriva em Python

Navegue pelos perigos do desvio de modelo e explore nosso guia prático para o monitoramento do desvio de dados.
Moez Ali's photo

Moez Ali

9 min

tutorial

Tratamento de exceções e erros em Python

Erros e exceções podem levar à falha do programa ou a um comportamento inesperado, e o Python vem com um conjunto robusto de ferramentas para melhorar a estabilidade do código.
Abid Ali Awan's photo

Abid Ali Awan

21 min

tutorial

Otimização em Python: Técnicas, pacotes e práticas recomendadas

Este artigo ensina a você sobre otimização numérica, destacando diferentes técnicas. Ele discute os pacotes Python, como SciPy, CVXPY e Pyomo, e fornece um notebook DataLab prático para você executar exemplos de código.
Kurtis Pykes 's photo

Kurtis Pykes

19 min

tutorial

Principais técnicas para lidar com valores ausentes que todo cientista de dados deve conhecer

Explore várias técnicas para lidar eficientemente com valores ausentes e suas implementações em Python.
Zoumana Keita 's photo

Zoumana Keita

15 min

Ver maisVer mais