Os vazamentos de memória estão sempre ok? [fechadas]

231

É sempre aceitável ter um vazamento de memória no aplicativo C ou C ++?

E se você alocar alguma memória e usá-la até a última linha de código do seu aplicativo (por exemplo, o destruidor de um objeto global)? Contanto que o consumo de memória não cresça com o tempo, não há problema em confiar no sistema operacional para liberar sua memória quando o aplicativo terminar (no Windows, Mac e Linux)? Você consideraria isso um vazamento de memória real se a memória estivesse sendo usada continuamente até ser liberada pelo sistema operacional.

E se uma biblioteca de terceiros forçar essa situação com você? Recusaria usar essa biblioteca de terceiros, não importa quão grande ela possa ser?

Eu vejo apenas uma desvantagem prática, e é que esses vazamentos benignos aparecerão com as ferramentas de detecção de vazamento de memória como falsos positivos.

Imbue
fonte
50
Se o consumo de memória não aumentar com o tempo, não será um vazamento.
precisa saber é
4
A maioria dos aplicativos (incluindo todos os programas .NET) possui pelo menos alguns buffers alocados uma vez e nunca são liberados explicitamente. Portanto, a definição do mpez0 é mais útil.
Ben Voigt
2
Sim, se você tiver memória infinita.
usuário
Um vazamento "benigno" (se houver) não é um falso positivo - é um vazamento que foi detectado corretamente. A detecção de vazamentos, mesmo para vazamentos que você pessoalmente não deseja consertar, é a razão de existência de um detector de vazamentos.
cHao
1
@ mpez0 "Se o consumo de memória não aumentar com o tempo, não será um vazamento"? Essa não é a definição de vazamento de memória. Um vazamento é a memória que vazou, o que significa que não foi liberado e você não tem mais referência a ele; portanto, é impossível você libertá-lo novamente. Se cresce ou não, é irrelevante.
Mecki

Respostas:

329

Não.

Como profissionais, a pergunta que não devemos nos perguntar é: "É certo fazer isso?" mas sim "Existe sempre um boa razão para fazer isso?" E "caçar esse vazamento de memória é uma dor" não é uma boa razão.

Eu gosto de manter as coisas simples. E a regra simples é que meu programa não tenha vazamentos de memória.

Isso também torna minha vida simples. Se eu detectar um vazamento de memória, eu o elimino, em vez de executar alguma estrutura elaborada da árvore de decisão para determinar se é um vazamento de memória "aceitável".

É semelhante aos avisos do compilador - o aviso será fatal para meu aplicativo em particular? Talvez não.

Mas, em última análise, é uma questão de disciplina profissional. Tolerar avisos do compilador e tolerar vazamentos de memória é um mau hábito que acabará me mordendo pela retaguarda.

Para levar as coisas ao extremo, seria aceitável para um cirurgião deixar algum equipamento operacional dentro de um paciente?

Embora seja possível que ocorra uma circunstância em que o custo / risco de remover essa peça de equipamento exceda o custo / risco de deixá-la dentro e que possa haver circunstâncias em que ela foi inofensiva, se eu vi essa pergunta postada no SurgeonOverflow.com e vi qualquer resposta diferente de "não", seria seriamente minar minha confiança na profissão médica.

-

Se uma biblioteca de terceiros me forçar a situação, isso levaria a suspeitar seriamente a qualidade geral da biblioteca em questão. Seria como se eu testasse dirigisse um carro e encontrasse duas arruelas e porcas soltas em um dos porta-copos - pode não ser um grande problema, mas retrata a falta de compromisso com a qualidade, por isso considero alternativas.

JohnMcG
fonte
57
Verdadeiro e não verdadeiro ao mesmo tempo. No final, a maioria de nós é escrava assalariada e qualquer desejo de artesanato deve ficar atrás das exigências do negócio. Se essa biblioteca 3o partido tem um vazamento e salva 2 semanas de trabalho, pode haver um caso de negócios para usá-lo, etc ...
Cervo
3
Eu usaria a biblioteca de qualquer maneira, se fosse algo que eu precisasse e não houvesse alternativas decentes, mas registraria um bug com os mantenedores.
tloach
7
Embora eu pessoalmente tenha exatamente a mesma resposta, existem programas que dificilmente liberam memória. O motivo é que eles são: a) destinados a rodar em sistemas operacionais que liberam memória eb) projetados para não serem executados por muito tempo. Restrições raras para um programa, de fato, mas aceito isso como perfeitamente válido.
2
Para adicionar alguns motivos para a verificação antecipada: quando suas ferramentas de depuração são inundadas com vazamentos "benignos", como você encontrará o "real"? Se você adicionar um recurso em lote, e de repente seu vazamento de 1K / hora se torna um 1K / segundo?
Peterchen
5
Hmm "não está vazando memória" "perfeito"?
JohnMcG 01/09/10
80

Não o considero um vazamento de memória, a menos que a quantidade de memória "usada" continue crescendo. Ter alguma memória não liberada, embora não seja ideal, não é um grande problema, a menos que a quantidade de memória necessária continue crescendo.

Jim C
fonte
12
Tecnicamente, um vazamento é a memória alocada e todas as referências a ele são perdidas. Não desalocar a memória no final é apenas preguiçoso.
Martin Iorque
17
Se você tiver um vazamento de memória único de 4 GB, isso é um problema.
John Dibling 7/11
21
Não importa se está crescendo ou não. Outros programas não podem usar a memória se você a tiver alocado.
Bill o Lagarto
8
> Outros programas não podem usar a memória se você a tiver alocado. Bem, o sistema operacional sempre pode trocar sua memória para o disco e permitir que outros aplicativos usem a RAM da qual você não estava aproveitando.
Max Lybbert
4
Se o programa tiver vida curta, um vazamento pode não ser tão ruim. Além disso, embora NÃO seja o ideal, a paginação não é tão cara quanto alguns fazem parecer, porque o programa não está interessado nessa memória (e, portanto, não estará trocando o tempo todo) - a menos que, é claro, você tenha um GC ...
Arafangion 27/03/09
79

Vamos corrigir nossas definições primeiro. Uma memoria vazamento de ocorre quando a memória é alocada dinamicamente, por exemplo, com malloc(), e todas as referências à memória são perdidas sem a correspondente liberação livre. Uma maneira fácil de fazer um é assim:

#define BLK ((size_t)1024)
while(1){
    void * vp = malloc(BLK);
}

Observe que toda vez que o loop while (1), 1024 (+ overhead) bytes são alocados e o novo endereço é atribuído ao vp; não há ponteiro restante para os blocos comerciais anteriores. É garantido que este programa seja executado até que o heap se esgote, e não há como recuperar a memória do malloc'ed. A memória está "vazando" da pilha, para nunca mais ser vista.

O que você está descrevendo, no entanto, soa como

int main(){
    void * vp = malloc(LOTS);
    // Go do something useful
    return 0;
}

Você aloca a memória, trabalha com ela até o programa terminar. Isto é não um vazamento de memória; isso não prejudica o programa, e toda a memória será eliminada automaticamente quando o programa terminar.

Geralmente, você deve evitar vazamentos de memória. Primeiro, como a altitude acima de você e o combustível no hangar, a memória que vazou e não pode ser recuperada é inútil; segundo, é muito mais fácil codificar corretamente, sem vazar memória, no início do que encontrar um vazamento de memória posteriormente.

Charlie Martin
fonte
Agora considere algumas dezenas dessas alocações. Agora considere mover o corpo "principal" para uma rotina chamada várias vezes. Aproveitar. - Concordo com o sentimento de que não é um problema tão grande nesse cenário, mas os cenários mudam. Como se costuma dizer, sempre escreva um código como se o responsável pela manutenção soubesse onde você mora.
Peterchen
2
Bem, o ponto é que a memória que é alocada e mantida até o programa chamar _exit () não é "vazada".
Charlie Martin
1
É um vazamento de memória e pode prejudicar seu programa. Alocações futuras podem falhar nesse processo, porque tenho certeza de que você está verificando se o malloc retornou nulo em todos os lugares. usando demais a memória, como em uma situação embutida onde a memória é escassa, essa pode ser a diferença entre a vida e a morte.
MikeJ
10
Mike, isso não é verdade. Em um ambiente C compatível, o encerramento de main libera todos os recursos do processo. Em um ambiente incorporado como você descreve, você pode ver essa situação, mas não teria uma principal. Agora, admitirei que pode haver ambientes incorporados defeituosos para os quais isso não seria verdade, mas depois vi ambientes defeituosos que não conseguiam lidar com + = corretamente também.
Charlie Martin
3
Sim, você agora descobriu que, se você tem mallocmuita memória, é uma coisa ruim. Ainda não é um vazamento . Não é um vazamento até e a menos que seja uma mallocmemória para a qual a referência é perdida.
Charlie Martin
39

Na teoria não, na prática depende .

Realmente depende da quantidade de dados que o programa está trabalhando, da frequência com que o programa é executado e se está ou não sendo executado constantemente.

Se eu tiver um programa rápido que leia uma pequena quantidade de dados faça um cálculo e saia, um pequeno vazamento de memória nunca será percebido. Como o programa não está sendo executado por muito tempo e usa apenas uma pequena quantidade de memória, o vazamento será pequeno e liberado quando o programa existir.

Por outro lado, se eu tiver um programa que processe milhões de registros e seja executado por um longo tempo, um pequeno vazamento de memória pode derrubar a máquina com tempo suficiente.

Quanto às bibliotecas de terceiros com vazamentos, se causarem um problema, corrija a biblioteca ou encontre uma alternativa melhor. Se não causar um problema, isso realmente importa?

vfilby
fonte
Não sei se você leu toda a minha pergunta ou não. Estou dizendo que a memória é usada até o final do aplicativo. Não cresce com o tempo. O único não não é que não há uma chamada para liberar / excluir.
Imbue
2
Então não é realmente um vazamento de memória. Um vazamento de memória é uma quantidade pequena de memória não utilizada, mas não liberada, essa quantidade aumenta com o tempo. O que você está falando é uma gota de memória. Não se preocupe com isso, a menos que sua gota seja muito grande.
vfilby
"Se não causar um problema, isso realmente importa?" Não, isso não importa. Eu gostaria que mais pessoas entendessem isso, em vez de se tornarem religiosas.
Imbue
2
@ John: Isso geralmente é menos uma questão de desenvolvedores preguiçosos e mais uma questão de desenvolvimento de software. Todos cometemos erros, os bugs são nossa profissão; nós os fazemos, nós os consertamos, é isso que fazemos. É sempre um equilíbrio entre custo inicial e manutenção a longo prazo, esse equilíbrio nunca é simples.
vfilby
1
John, eu concordo 100% com você. Imbum A questão é quase "quanto você aceita". Desleixado é desleixado .. Que tal deixar um camarão atrás do seu monitor. fedor é fedor. Toda vez que caímos, nossa indústria desmorona um pouco. Se você sabe que há um vazamento e sabe que o causou, deve corrigi-lo.
precisa saber é
37

Muitas pessoas parecem ter a impressão de que, uma vez liberada a memória, ela é instantaneamente retornada ao sistema operacional e pode ser usada por outros programas.

Isso não é verdade. Os sistemas operacionais geralmente gerenciam memória em páginas 4KiB. malloce outros tipos de gerenciamento de memória obtêm páginas do sistema operacional e as sub-gerenciam como bem entenderem. É bastante provável que free()irá não retornar páginas para o sistema operacional, sob a suposição de que seu programa irá malloc mais memória mais tarde.

Não estou dizendo que free()nunca devolve memória ao sistema operacional. Isso pode acontecer, principalmente se você estiver liberando grandes extensões de memória. Mas não há garantia.

O fato importante: se você não liberar a memória da qual não precisa mais, garantimos que outros mallocs consumirão ainda mais memória. Mas se você liberar primeiro, o malloc poderá reutilizar a memória liberada.

O que isso significa na prática? Isso significa que, se você sabe que seu programa não exigirá mais memória a partir de agora (por exemplo, está na fase de limpeza), liberar memória não é tão importante. No entanto, se o programa puder alocar mais memória posteriormente, evite vazamentos de memória - principalmente aqueles que podem ocorrer repetidamente.

Consulte também este comentário para obter mais detalhes sobre por que liberar memória pouco antes da finalização é ruim.

Um comentarista não pareceu entender esse chamado free() não permite automaticamente que outros programas usem a memória liberada. Mas esse é o ponto inteiro desta resposta!

Portanto, para convencer as pessoas, demonstrarei um exemplo em que free () faz muito pouco bem. Para facilitar a matemática, vou fingir que o sistema operacional gerencia memória em páginas de 4000 bytes.

Suponha que você aloque dez mil blocos de 100 bytes (por simplicidade, ignorarei a memória extra necessária para gerenciar essas alocações). Isso consome 1 MB ou 250 páginas. Se você liberar 9000 desses blocos aleatoriamente, ficará com apenas 1000 blocos - mas eles estão espalhados por todo o lugar. Estatisticamente, cerca de 5 páginas estarão vazias. Os outros 245 terão cada um pelo menos um bloco alocado. Isso equivale a 980 KB de memória, que não pode ser recuperado pelo sistema operacional - mesmo que agora você tenha apenas 100 KB alocados!

Por outro lado, agora você pode malloc () 9000 blocos a mais sem aumentar a quantidade de memória que seu programa está acumulando.

Mesmo quando tecnicamentefree() poderia retornar memória ao sistema operacional, talvez não o fizesse. precisa alcançar um equilíbrio entre operar rapidamente e economizar memória. Além disso, um programa que já alocou muita memória e liberou, provavelmente o fará novamente. Um servidor da web precisa manipular solicitação após solicitação após solicitação - faz sentido manter alguma memória "folga" disponível para que você não precise solicitar memória ao sistema operacional o tempo todo.free()

rots Artelius
fonte
1
E se, outros programas exigem a memória que seu programa está segurando desnecessariamente, portanto, mesmo que você pode não precise mais mallocs, free () os espaços de memória não utilizados :)
MN
2
Você perdeu totalmente o meu argumento. Quando você libera () memória, outros programas não podem usá-la !! (Às vezes, eles podem, principalmente se você liberar grandes blocos de memória. Mas, muitas vezes, eles não podem!) Editarei minha postagem para deixar isso mais claro.
Artelius
27

Não há nada errado em termos de limpeza do sistema operacional após a execução do aplicativo.

Realmente depende do aplicativo e como ele será executado. É preciso cuidar de vazamentos que ocorrem continuamente em um aplicativo que precisa ser executado por semanas, mas uma pequena ferramenta que calcula um resultado sem uma necessidade de memória muito alta não deve ser um problema.

Há uma razão pela qual muitas linguagens de script não coletam lixo referências cíclicas ... para seus padrões de uso, não é um problema real e, portanto, seria tanto desperdício de recursos quanto a memória desperdiçada.

kasperjj
fonte
Sobre linguagens de script: Python usa refcounting, mas possui um GC apenas para liberar referências cíclicas. Em outras linguagens, o programador geralmente evita referências explicitamente cíclicas, o que cria outros problemas.
Blaisorblade 12/01/09
As versões anteriores do PHP não liberavam memória, apenas rodavam do começo ao fim, crescendo em memória - após os 0,1 segundos de tempo de execução, o script seria encerrado e toda a memória seria recuperada.
Arafangion
19

Acredito que a resposta é não, nunca permita vazamento de memória e tenho alguns motivos que não vi explicitamente declarados. Existem ótimas respostas técnicas aqui, mas acho que a resposta real depende de mais razões sociais / humanas.

(Primeiro, observe que, como outros mencionados, um verdadeiro vazamento ocorre quando o programa, a qualquer momento, perde o controle dos recursos de memória alocados. Em C, isso acontece quando você direciona malloc()um ponteiro e deixa esse ponteiro sair do escopo sem fazer uma ação free()primeiro.)

O ponto crucial da sua decisão aqui é o hábito. Quando você codifica em um idioma que usa ponteiros, você usa muito os ponteiros . E ponteiros são perigosos; elas são a maneira mais fácil de adicionar todo tipo de problemas graves ao seu código.

Quando você está codificando, às vezes você fica com a bola e às vezes fica cansado, bravo ou preocupado. Durante esses tempos um pouco distraídos, você está codificando mais no piloto automático. O efeito do piloto automático não diferencia entre código único e um módulo em um projeto maior. Durante esses períodos, os hábitos que você estabelecer são o que acabará na sua base de código.

Portanto, nunca permita vazamentos de memória pela mesma razão que você ainda deve verificar seus pontos cegos ao mudar de faixa, mesmo se você for o único carro na estrada no momento. Durante os momentos em que seu cérebro ativo está distraído, bons hábitos são tudo o que pode salvá-lo de erros desastrosos.

Além da questão do "hábito", os indicadores são complexos e geralmente exigem muito poder do cérebro para rastrear mentalmente. É melhor não "enlamear a água" quando se trata de usar ponteiros, especialmente quando você é iniciante em programação.

Há um aspecto mais social também. Com o uso adequado de malloc()e free(), qualquer pessoa que consulte seu código ficará à vontade; você está gerenciando seus recursos. Caso contrário, eles suspeitarão imediatamente de um problema.

Talvez você tenha percebido que o vazamento de memória não prejudica nada nesse contexto, mas todo mantenedor do seu código também terá que resolver isso na cabeça dele quando ler esse trecho de código. Ao usar, free()você remove a necessidade de considerar o problema.

Finalmente, a programação está escrevendo um modelo mental de processo em uma linguagem inequívoca, para que uma pessoa e um computador possam entender perfeitamente o processo. Uma parte vital das boas práticas de programação nunca é introduzir ambiguidade desnecessária.

A programação inteligente é flexível e genérica. Uma programação ruim é ambígua.

Jason L
fonte
Eu amo a idéia do hábito. Eu também concordo. Se vejo um vazamento de memória, sempre me pergunto em que outro canto o codificador cortou. Especialmente se é óbvio
baash05
Esta é a melhor resposta de longe. Estou programando em C ++ há 5 anos e nunca escrevi um único vazamento de memória. O motivo é que não escrevo códigos que tendem a vazar memória. O bom design do C ++ é usado raramente new, o que elimina a maioria dos vazamentos de memória imediatamente. Somente se você absolutamente precisar usá-lo new. O resultado disso newdeve ser imediatamente colocado em um ponteiro inteligente. Se você seguir essas duas regras, simplesmente nunca vazará memória (exceto um bug em uma biblioteca). O único caso restante são os shared_ptrciclos, caso em que você precisa saber para usar weak_ptr.
David Stone
15

Acho que na sua situação a resposta pode ser que está tudo bem. Mas você definitivamente precisa documentar que o vazamento de memória é uma decisão consciente. Você não quer que um programador de manutenção apareça, coloque seu código em uma função e chame um milhão de vezes. Portanto, se você decidir que um vazamento está correto, é necessário documentá-lo (EM GRANDES LETRAS) para quem precisar trabalhar no programa no futuro.

Se essa é uma biblioteca de terceiros, você pode ficar preso. Mas definitivamente documente que esse vazamento ocorre.

Mas, basicamente, se o vazamento de memória é uma quantidade conhecida, como um buffer de 512 KB ou algo assim, não é um problema. Se o vazamento de memória continuar crescendo, como sempre que você chama uma biblioteca, sua memória aumenta em 512 KB e não é liberada, então você pode ter um problema. Se você o documentar e controlar o número de vezes que a chamada é executada, poderá ser gerenciável. Mas você realmente precisa de documentação porque, embora 512 não seja muito, 512 mais de um milhão de chamadas são muitas.

Além disso, você precisa verificar a documentação do sistema operacional. Se este era um dispositivo incorporado, pode haver sistemas operacionais que não liberam toda a memória de um programa que sai. Não tenho certeza, talvez isso não seja verdade. Mas vale a pena investigar.

Cervo
fonte
3
"Mas você definitivamente precisa documentar que o vazamento de memória é uma decisão consciente". Graças aos céus. O melhor ponto levantado até agora.
pestófago 07/11/08
15

Vou dar a resposta impopular, mas prática, de que é sempre errado liberar memória, a menos que isso reduza o uso de memória do seu programa . Por exemplo, um programa que faz uma única alocação ou uma série de alocações para carregar o conjunto de dados que ele usará durante toda a sua vida útil não precisa liberar nada. No caso mais comum de um programa grande com requisitos de memória muito dinâmicos (pense em um navegador da web), você obviamente deve liberar memória que não está mais usando o mais rápido possível (por exemplo, fechando uma guia / documento / etc.) , mas não há motivo para liberar nada quando o usuário seleciona cliques em "sair", e isso é realmente prejudicial à experiência do usuário.

Por quê? Liberar memória requer tocar na memória. Mesmo que a implementação do malloc do sistema não armazene metadados adjacentes aos blocos de memória alocados, você provavelmente estará andando por estruturas recursivas apenas para encontrar todos os indicadores necessários para liberar.

Agora, suponha que seu programa tenha trabalhado com um grande volume de dados, mas não tenha tocado na maioria deles por um tempo (novamente, o navegador da web é um ótimo exemplo). Se o usuário estiver executando muitos aplicativos, uma boa parte desses dados provavelmente foi trocada para o disco. Se você simplesmente sair (0) ou retornar do main, ele sai instantaneamente. Ótima experiência do usuário. Se você se esforçar para tentar liberar tudo, poderá gastar 5 segundos ou mais trocando todos os dados novamente, apenas para jogá-los fora imediatamente depois disso. Perda de tempo do usuário. Desperdício da vida da bateria do laptop. Desperdício de desgaste no disco rígido.

Isso não é apenas teórico. Sempre que me vejo com muitos aplicativos carregados e o disco começa a ser debulhado, nem considero clicar em "sair". Chego a um terminal o mais rápido possível e digito killall -9 ... porque sei que "exit" apenas piorará.

R .. GitHub PARE DE AJUDAR O GELO
fonte
5
Adore esta citação de Raymond Chen: "O prédio está sendo demolido. Não se preocupe em varrer o chão, esvaziar as latas de lixo e apagar os quadros brancos. E não fazer fila na saída do prédio, para que todos possam se mudar / tudo o que você está fazendo é fazer a equipe de demolição esperar que você termine essas tarefas inúteis de limpeza da casa ". ( blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683 )
Andreas Magnusson
11

Tenho certeza de que alguém pode apresentar um motivo para dizer Sim, mas não sou eu. Em vez de dizer não, vou dizer que isso não deve ser uma pergunta de sim / não. Existem maneiras de gerenciar ou conter vazamentos de memória, e muitos sistemas os possuem.

Existem sistemas da NASA em dispositivos que deixam a Terra planejando isso. Os sistemas serão reiniciados automaticamente de vez em quando, para que vazamentos de memória não sejam fatais para a operação geral. Apenas um exemplo de contenção.

pearcewg
fonte
Na verdade, esse é um exemplo de envelhecimento do software. Assunto fascinante do estudo.
Konrad Rudolph
Uma reinicialização automática de vez em quando, não é? NASA, hein? (* olha para CDs de instalação do Microsoft Windows antigos *) Isso explica tanto ...
Christian Severin
8

Se você alocar memória e usá-la até a última linha do seu programa, isso não será um vazamento. Se você alocar memória e esquecê-la, mesmo que a quantidade de memória não esteja aumentando, isso é um problema. Essa memória alocada, mas não utilizada, pode fazer com que outros programas fiquem mais lentos ou nem um pouco.

Bill the Lizard
fonte
Na verdade, não, pois, se não for utilizado, será apenas paginado. Quando o aplicativo sai, toda a memória é liberada.
Eclipse Eclipse
Desde que alocado, outros programas não poderão usá-lo. Não será paginado se você não desalocá-lo.
Bill o Lagarto
Claro que sim - é disso que trata a memória virtual. Você pode ter 1 GB de RAM real e, no entanto, ter 4 processos, cada um alocando totalmente 2 GB de memória virtual (desde que o seu arquivo de paginação seja grande o suficiente).
Eclipse em Eclipse
Obviamente, você terá problemas desagradáveis ​​de paginação se cada um desses processos estiver usando ativamente toda essa memória.
Eclipse em Eclipse
Ok, eu entendo o que você está falando agora. Se você desalocar a memória que não está usando, reduzirá a necessidade de paginação. Se você mantê-lo alocados, sua aplicação ainda vai mantê-lo quando ele está de volta paginado no.
Bill o Lagarto
8

Posso contar por um lado o número de vazamentos "benignos" que vi ao longo do tempo.

Portanto, a resposta é um sim muito qualificado.

Um exemplo. Se você possui um recurso singleton que precisa de um buffer para armazenar uma fila ou deque circular, mas não sabe qual o tamanho do buffer e não pode suportar a sobrecarga do bloqueio ou de cada leitor, aloque um buffer que exponha a duplicação, mas não liberar os antigos vazará uma quantidade limitada de memória por fila / deque. A vantagem disso é que eles aceleram drasticamente todos os acessos e podem alterar os assintóticos das soluções de multiprocessadores, sem arriscar a disputa por um bloqueio.

Vi essa abordagem ser muito benéfica para coisas com contagens muito claramente definidas, como deques de roubo de trabalho por CPU e em um grau muito menor no buffer usado para armazenar o singleton /proc/self/maps estado no coletor de lixo conservador de Hans Boehm para C / C ++, que é usado para detectar os conjuntos raiz, etc.

Embora tecnicamente um vazamento, ambos os casos sejam limitados em tamanho e no trabalho circular expansível que rouba o caso deque, há uma enorme vitória de desempenho em troca de um fator limitado de 2 aumento no uso de memória para as filas.

Edward KMETT
fonte
1
Você pode usar indicadores de perigo para evitar o vazamento.
Demi
8

Se você alocar um monte de heap no início do seu programa, e não o liberar ao sair, isso não é um vazamento de memória em si. Um vazamento de memória ocorre quando o programa faz um loop em uma seção do código, e esse código aloca o heap e, em seguida, "perde o controle" dele sem liberá-lo.

De fato, não há necessidade de fazer chamadas para liberar () ou excluir antes de sair. Quando o processo termina, toda a sua memória é recuperada pelo sistema operacional (esse é certamente o caso do POSIX. Em outros sistemas operacionais - particularmente os incorporados - YMMV).

O único cuidado que eu teria ao não liberar a memória no momento da saída é que, se você refatorar seu programa para que, por exemplo, se torne um serviço que aguarda entrada, faça o que seu programa fizer, faça um loop para aguardar outra chamada de serviço, o que você codificou pode se transformar em um vazamento de memória.

nsayer
fonte
Eu peço desculpa mas não concordo. Isso é "um vazamento de memória em si".
21978 Konrad Rudolph
Não é um vazamento até que você "perca" a referência ao objeto. Presumivelmente, se a memória for usada durante toda a vida útil do programa, ela não vazará. Se a referência não for perdida até que exit () seja chamada, absolutamente não será um vazamento.
Nsayer 7/11
O Amiga DOS foi o último O / SI analisado que não foi limpo atrás dos processos. Lembre-se, no entanto, de que a memória compartilhada do System V IPC pode ser mantida, mesmo que nenhum processo esteja sendo usado.
Jonathan Leffler
O Palm não libera memória "vazada" até você hotsync. veio bem depois da amiga. Eu executei aplicativos no meu emulador de palma que apresentavam vazamentos. Eles nunca chegaram à minha palma de verdade.
precisa saber é
6

isso é tão específico do domínio que dificilmente vale a pena responder. use sua cabeça em pânico.

  • sistema operacional de ônibus espacial: não, nenhum vazamento de memória é permitido
  • código de prova de conceito de desenvolvimento rápido: consertar todos esses vazamentos de memória é uma perda de tempo.

e existe um espectro de situações intermediárias.

o custo de oportunidade ($$$) de adiar a liberação de um produto para corrigir todos os problemas, exceto os piores vazamentos de memória, geralmente diminui a sensação de ser "desleixado ou não profissional". Seu chefe paga para você ganhar dinheiro, não para ter sentimentos quentes e confusos.

Dustin Getz
fonte
2
Atitude muito míope. Você está basicamente dizendo que não há necessidade de usar práticas de programação fundamentalmente sólidas até que um defeito seja causado por essas práticas. O problema é que o software que é escrito usando métodos desleixados tende a ter mais defeitos do que o software que não é.
John Dibling
1
Eu não acredito nisso tudo. E o gerenciamento de memória é mais complicado do que escrever métodos limpos.
Dustin Getz
1
Dustin obviamente trabalha no mundo real como a maioria de nós, onde trabalhamos perpetuamente contra prazos insanos para acompanhar a concorrência. Portanto, lidar com bugs deve ser feito de maneira pragmática. Ao perder muito tempo com bugs sem importância em programas sem importância, você não fará suas coisas.
Wouter van Nifterick
O problema com essa atitude é: quando você começa a consertar os vazamentos? "OK, é uma usina de força, mas é apenas carvão, não urânio. Por que consertar vazamentos aqui?" - Aprendi no mundo real que, se você não faz a coisa certa desde o início, o tempo todo, isso nunca acontece. Essa atitude gera projetos "99% completos" após duas semanas e permanecem assim por dois meses.
Peterchen
5

Você deve primeiro perceber que há uma grande diferença entre um vazamento de memória percebido e um vazamento de memória real. Com muita frequência, as ferramentas de análise relatam muitos erros e rotulam algo como vazado (memória ou recursos como alças, etc.) onde realmente não está. Muitas vezes, isso ocorre devido à arquitetura da ferramenta de análise. Por exemplo, certas ferramentas de análise relatam objetos de tempo de execução como vazamentos de memória porque nunca os veem liberados. Mas a desalocação ocorre no código de desligamento do tempo de execução, que a ferramenta de análise pode não conseguir ver.

Com isso dito, ainda haverá momentos em que você terá vazamentos reais de memória que são muito difíceis de encontrar ou muito difíceis de corrigir. Então agora a questão é: está tudo bem em deixá-los no código?

A resposta ideal é "não, nunca". Uma resposta mais pragmática pode ser "não, quase nunca". Muitas vezes, na vida real, você tem um número limitado de recursos e tempo para resolver e uma lista interminável de tarefas. Quando uma das tarefas é eliminar vazamentos de memória, muitas vezes entra em vigor a lei dos retornos decrescentes. Você pode eliminar, digamos, 98% de todos os vazamentos de memória em um aplicativo em uma semana, mas os 2% restantes podem levar meses. Em alguns casos, pode até ser impossível eliminar certos vazamentos devido à arquitetura do aplicativo sem uma grande refatoração de código. Você precisa pesar os custos e os benefícios de eliminar os 2% restantes.

John Dibling
fonte
5

Nesse tipo de questão, o contexto é tudo. Pessoalmente, não suporto vazamentos e, no meu código, faço um grande esforço para corrigi-los se eles surgirem, mas nem sempre vale a pena consertar um vazamento, e quando as pessoas estão me pagando pela hora que tenho ocasionalmente disse-lhes que não valia a pena pagar uma correção no código deles. Deixe-me lhe dar um exemplo:

Eu estava supervisionando um projeto, realizando alguns trabalhos de aperfeiçoamento e corrigindo muitos bugs. Houve um vazamento durante a inicialização dos aplicativos que eu rastreei e compreendi completamente. Para corrigi-lo corretamente, seria necessário um dia ou mais para refatorar um pedaço de código funcional. Eu poderia ter feito algo hacky (como colocar o valor em um global e capturá-lo em algum momento, sei que não estava mais em uso para liberar), mas isso teria causado mais confusão ao próximo cara que precisou tocar no código.

Pessoalmente, eu não teria escrito o código dessa maneira em primeiro lugar, mas a maioria de nós nem sempre trabalha em bases de código bem desenhadas e bem desenhadas, e às vezes você precisa observar essas coisas de forma pragmática. A quantidade de tempo que levaria para corrigir esse vazamento de 150 bytes poderia ser gasto em aprimoramentos algorítmicos que eliminavam megabytes de memória RAM.

Por fim, decidi que não valia a pena consertar o vazamento de 150 bytes para um aplicativo usado em torno de um gig de memória ram e executado em uma máquina dedicada, por isso escrevi um comentário dizendo que havia vazamento, o que precisava ser alterado para corrigir e por que não valia a pena na época.

Louis Gerbarg
fonte
Inteligente. Especialmente porque o vazamento ocorreu durante a inicialização, o que significa que ele não se acumularia durante o tempo de execução do aplicativo.
Demi
5

Embora a maioria das respostas se concentre em vazamentos de memória real (que nunca são bons, porque são um sinal de codificação superficial), essa parte da pergunta parece mais interessante para mim:

E se você alocar alguma memória e usá-la até a última linha de código do seu aplicativo (por exemplo, o desconstrutor de um objeto global)? Contanto que o consumo de memória não cresça com o tempo, não há problema em confiar no sistema operacional para liberar sua memória quando o aplicativo terminar (no Windows, Mac e Linux)? Você consideraria isso um vazamento de memória real se a memória estivesse sendo usada continuamente até ser liberada pelo sistema operacional.

Se a memória associada for usada, você não poderá liberá-la antes que o programa termine. Se a liberação é feita pela saída do programa ou pelo sistema operacional, não importa. Enquanto isso estiver documentado, para que as alterações não apresentem vazamentos reais de memória e contanto que não haja destruidor de C ++ ou função de limpeza de C envolvida na imagem. Um arquivo não fechado pode ser revelado através de um FILEobjeto vazado , mas uma falta de fclose () também pode fazer com que o buffer não seja liberado.

Portanto, voltando ao caso original, o IMHO é perfeitamente bom em si, tanto que o Valgrind, um dos detectores de vazamento mais poderosos, tratará esses vazamentos apenas se solicitado. No Valgrind, quando você sobrescreve um ponteiro sem liberá-lo antes, ele é considerado um vazamento de memória, porque é mais provável que ocorra novamente e faça com que o heap cresça infinitamente.

Então, não há blocos de memória nfreed que ainda possam ser acessados. Pode-se garantir a libertação de todos eles na saída, mas isso é apenas uma perda de tempo. A questão é se eles poderiam ser libertados antes . Diminuir o consumo de memória é útil em qualquer caso.

Blaisorblade
fonte
Uau ... alguém que sabe o que é um vazamento de memória.
Simon Buchan
4

Eu concordo com o vfilby - depende. No Windows, tratamos os vazamentos de memória como erros relativamente graves. Mas, depende muito do componente.

Por exemplo, vazamentos de memória não são muito graves para componentes que são executados raramente e por períodos limitados. Esses componentes são executados, executam o trabalho e depois saem. Quando eles saem, toda a sua memória é liberada implicitamente.

No entanto, vazamentos de memória em serviços ou outros componentes de longo prazo (como o shell) são muito graves. A razão é que esses erros "roubam" a memória ao longo do tempo. A única maneira de recuperar isso é reiniciar os componentes. A maioria das pessoas não sabe como reiniciar um serviço ou o shell - por isso, se o desempenho do sistema sofrer, eles simplesmente reiniciarão.

Então, se você tiver um vazamento - avalie seu impacto de duas maneiras

  1. Para o seu software e a experiência do usuário.
  2. Para o sistema (e o usuário) em termos de economia com os recursos do sistema.
  3. Impacto da correção na manutenção e confiabilidade.
  4. Probabilidade de causar uma regressão em outro lugar.

Foredecker

Foredecker
fonte
3. Impacto na manutenção do software.
Peterchen
3

Mesmo se você tiver certeza de que seu vazamento de memória 'conhecido' não causará estragos, não faça isso. Na melhor das hipóteses, isso abrirá um caminho para você cometer um erro semelhante e provavelmente mais crítico em um horário e local diferentes.

Para mim, perguntar isso é como questionar "Posso quebrar o sinal vermelho às 3 da manhã quando ninguém está por perto?". Certamente, pode não causar nenhum problema naquele momento, mas fornecerá uma alavanca para você fazer o mesmo na hora do rush!

Ather
fonte
3

Não, você não deve ter vazamentos que o sistema operacional irá limpar para você. O motivo (não mencionado nas respostas acima, tanto quanto pude verificar) é que você nunca sabe quando seu main () será reutilizado como função / módulo em outro programa . Se o seu main () passa a ser uma função freqüentemente chamada no software de outras pessoas - esse software terá um vazamento de memória que consome memória ao longo do tempo.

KIV


fonte
3

Eu acho que tudo bem se você estiver escrevendo um programa destinado a vazar memória (isto é, para testar o impacto de vazamentos de memória no desempenho do sistema).

Bip Bip
fonte
3

Estou surpreso ao ver tantas definições incorretas do que realmente é um vazamento de memória. Sem uma definição concreta, uma discussão sobre se é algo ruim ou não não vai a lugar algum.

Como alguns comentaristas apontaram corretamente, um vazamento de memória ocorre apenas quando a memória alocada por um processo sai do escopo na medida em que o processo não é mais capaz de fazer referência ou excluí-lo.

Um processo que capta cada vez mais memória não está necessariamente vazando. Desde que seja capaz de referenciar e desalocar essa memória, ela permanece sob o controle explícito do processo e não vazou. O processo pode muito bem ser mal projetado, especialmente no contexto de um sistema em que a memória é limitada, mas isso não é o mesmo que um vazamento. Por outro lado, perder o escopo de, digamos, um buffer de 32 bytes ainda é um vazamento, mesmo que a quantidade de memória vazada seja pequena. Se você acha que isso é insignificante, aguarde até que alguém envolva um algoritmo na chamada da sua biblioteca e o chame 10.000 vezes.

Não vejo nenhuma razão para permitir vazamentos em seu próprio código, por menor que seja. As linguagens de programação modernas, como C e C ++, se esforçam muito para ajudar os programadores a evitar tais vazamentos e raramente há um bom argumento para não adotar boas técnicas de programação - especialmente quando combinadas com recursos específicos de linguagem - para evitar vazamentos.

No que diz respeito ao código existente ou de terceiros, em que seu controle sobre a qualidade ou a capacidade de fazer uma alteração pode ser altamente limitado, dependendo da gravidade do vazamento, você pode ser forçado a aceitar ou tomar medidas mitigadoras, como reiniciar seu processo regularmente para reduzir o efeito do vazamento.

Pode não ser possível alterar ou substituir o código existente (vazando) e, portanto, você pode aceitá-lo. No entanto, isso não é o mesmo que declarar que está OK.

Componente 10
fonte
2

Realmente não é um vazamento, se é intencional e não é um problema, a menos que seja uma quantidade significativa de memória ou pode crescer para ser uma quantidade significativa de memória. É bastante comum não limpar alocações globais durante a vida útil de um programa. Se o vazamento ocorrer em um servidor ou aplicativo de longa duração, crescer com o tempo, isso é um problema.

Sanjaya R
fonte
2

Eu acho que você respondeu sua própria pergunta. A maior desvantagem é como elas interferem nas ferramentas de detecção de vazamento de memória, mas acho que essa desvantagem é enorme para certos tipos de aplicativos.

Eu trabalho com aplicativos de servidor legados que deveriam ser sólidos, mas eles têm vazamentos e os globais atrapalham as ferramentas de detecção de memória. É um grande negócio.

No livro "Collapse", de Jared Diamond, o autor se pergunta sobre o que o cara estava pensando que cortou a última árvore na Ilha de Páscoa, a árvore que ele precisaria para construir uma canoa para sair da ilha. Eu me pergunto sobre o dia de muitos anos atrás em que a primeira global foi adicionada à nossa base de código. Esse foi o dia em que deveria ter sido pego.

Corey Trager
fonte
2

Vejo o mesmo problema em todas as perguntas do cenário como esta: O que acontece quando o programa muda e, de repente, esse pequeno vazamento de memória é chamado dez milhões de vezes e o final do programa está em um local diferente, então isso importa? Se estiver em uma biblioteca, registre um bug com os mantenedores da biblioteca, não coloque um vazamento em seu próprio código.

abordagem
fonte
Nesse caso, o impacto do vazamento de memória é alterado e você precisa reavaliar a prioridade de obstruir o vazamento.
John Dibling 7/11
@ John: É melhor você pelo menos documentar o vazamento então. Mesmo assim, eu não confiaria em alguém para não ignorar um grande comentário vermelho piscando e copiar e colar códigos vazados de qualquer maneira. Prefiro não dar a alguém a capacidade de fazer isso em primeiro lugar.
tloach
2

Eu vou responder não.

Em teoria, o sistema operacional será limpo após você se você deixar uma bagunça (agora isso é rude, mas como os computadores não têm sentimentos, pode ser aceitável). Mas você não pode prever todas as situações possíveis que possam ocorrer quando o programa for executado. Portanto (a menos que você consiga realizar uma prova formal de algum comportamento), criar vazamentos de memória é irresponsável e desleixado do ponto de vista profissional.

Se um componente de terceiros vazar memória, esse é um argumento muito forte contra seu uso, não apenas por causa do efeito iminente, mas também porque mostra que os programadores trabalham de maneira desleixada e que isso também pode afetar outras métricas. Agora, ao considerar sistemas legados, isso é difícil (considere os componentes de navegação na Web: que eu saiba, todos eles vazam memória), mas deve ser a norma.

Konrad Rudolph
fonte
2

Historicamente, isso importava em alguns sistemas operacionais em alguns casos extremos. Esses casos extremos podem existir no futuro.

Aqui está um exemplo: no SunOS na era Sun 3, havia um problema: se um processo usasse exec (ou mais tradicionalmente fork e, em seguida, exec), o novo processo subsequente herdaria o mesmo espaço de memória que o pai e não poderia ser reduzido . Se um processo pai alocasse 1/2 gig de memória e não a liberasse antes de chamar o exec, o processo filho começaria a usar esse mesmo 1/2 gig (mesmo que não tenha sido alocado). Esse comportamento foi melhor exibido pelo SunTools (seu sistema de janelas padrão), que era um porco da memória. Todos os aplicativos gerados foram criados via fork / exec e herdaram a pegada do SunTools, preenchendo rapidamente o espaço de troca.

plinto
fonte
2

Isso já foi discutido ad nauseam . Resumindo, um vazamento de memória é um bug e deve ser corrigido. Se uma biblioteca de terceiros vaza memória, ele se pergunta o que mais há de errado com ela, não? Se você estivesse construindo um carro, usaria um motor que ocasionalmente vaza óleo? Afinal, alguém fez o motor, então não é sua culpa e você não pode consertá-lo, certo?

Dima
fonte
Mas se você era dono de um carro com um motor que ocasionalmente vaza óleo, gasta dinheiro para consertá-lo ou fica de olho nos níveis de óleo e reabastece-o de vez em quando. A resposta depende de todos os tipos de fatores.
magro
Não se trata de possuir um carro. Trata-se de construir um carro. Se você obtém uma biblioteca de terceiros com vazamento de memória e precisa absolutamente usá-la, então vive com ela. Mas se você é quem está escrevendo um sistema ou uma biblioteca, é de sua responsabilidade garantir que esteja livre de erros.
Dima
Marcar com +1 como qualquer outro bug. (Isso não significa "correção instantaneamente" em meu livro, mas "precisa befixed" com certeza)
Peterchen
2

Geralmente, um vazamento de memória em um aplicativo independente não é fatal, pois é limpo quando o programa é encerrado.

O que você faz com os programas de servidor projetados para que não saiam?

Se você é o tipo de programador que não cria e implementa código em que os recursos são alocados e liberados corretamente, não quero nada com você ou seu código. Se você não se importa de limpar sua memória vazada, e as fechaduras? Você os deixa lá fora também? Você deixa pequenos pedaços de arquivos temporários espalhados em vários diretórios?

Vazou essa memória e deixou o programa limpá-la? Não. Absolutamente não. É um mau hábito, que leva a bugs, bugs e mais bugs.

Limpe depois de si mesmo. Sua mãe não trabalha mais aqui.

EvilTeach
fonte
Trabalhei em programas de servidor que deliberadamente usam processos em vez de threads, para que vazamentos de memória e falhas de segmentação causem danos limitados.
magro
Abordagem interessante. Eu ficaria um pouco preocupado com os processos que não conseguem sair e continuam consumindo memória.
EvilTeach
2

Como regra geral, se você tem vazamentos de memória que considera que não pode evitar, precisa pensar mais sobre a propriedade do objeto.

Mas, para sua pergunta, minha resposta, em poucas palavras, é No código de produção, sim. Durante o desenvolvimento, não . Isso pode parecer inverso, mas eis o meu raciocínio:

Na situação que você descreve, onde a memória é mantida até o final do programa, não há problema em não liberá-la. Quando o processo terminar, o sistema operacional será limpo de qualquer maneira. De fato, isso pode melhorar a experiência do usuário: em um jogo em que trabalhei, os programadores pensaram que seria mais fácil liberar toda a memória antes de sair, fazendo com que o desligamento do programa levasse meio minuto! Uma mudança rápida que acabou de chamar exit () fez o processo desaparecer imediatamente e colocou o usuário de volta na área de trabalho onde ele queria estar.

No entanto, você está certo sobre as ferramentas de depuração: elas funcionam bem, e todos os falsos positivos podem fazer com que encontrar sua memória real vaze uma dor. E, por isso, sempre escreva o código de depuração que libera a memória e desative-o quando você enviar.

Enno
fonte