É uma perda de tempo liberar recursos antes de sair de um processo? [duplicado]

62

Vamos considerar um programa fictício que cria uma lista vinculada no heap e, no final do programa, há um loop que libera todos os nós e, em seguida, sai. Para este caso, digamos que a lista encadeada tenha apenas 500 K de memória, e nenhum gerenciamento de espaço especial seja necessário.

  • Isso é uma perda de tempo, porque o sistema operacional fará isso de qualquer maneira?
  • Haverá um comportamento diferente mais tarde?
  • Isso é diferente de acordo com a versão do SO?

Estou interessado principalmente em sistemas baseados em UNIX, mas qualquer informação será apreciada. Eu tive hoje a minha primeira aula sobre o curso de sistemas operacionais e estou pensando sobre isso agora.

Edit: Já que muitas pessoas aqui estão preocupadas com os efeitos colaterais, e em geral com 'boas práticas de programação' e assim. Você está certo! Eu concordo 100% com suas declarações. Mas a minha pergunta é apenas hipotética, quero saber como o SO gerencia isso. Então, por favor, deixe de fora coisas como 'encontrar outros bugs ao liberar toda a memória'.

    
por Kahil 05.08.2015 / 21:05
fonte

16 respostas

18

OK, recebi um e-mail de volta do meu instrutor, com uma resposta muito boa e razoável. Aqui está:

Hi Ramzi,

Thanks for the link to the interesting messages thread which you started.

As per our discussion, malloc operates on the process' virtual memory. So, when the process dies, its virtual address space "disappears", and any physical memory mapped to it is freed. Hence, disregarding "good software engineering practices" and such, dynamic memory de-allocation just before exiting a process is indeed a waste of time.

(Needless to say, this is not the case when a single thread terminates but other threads of that process keep executing.)

Então, de acordo com isso:

  • É uma perda de tempo
  • Não afetará mais tarde
  • É independente das versões do sistema operacional.
por 09.10.2016 / 15:06
fonte
67

Meu principal problema com a sua abordagem é que uma ferramenta de detecção de vazamentos (como Valgrind) irá reportá-la e você começará a ignorá-la. Então, algum dia um vazamento real pode aparecer, e você nunca vai notar por causa de todo o barulho.

    
por 19.03.2012 / 16:00
fonte
39

Uma vez eu tive que implementar um algoritmo usando deques que foram alocados dinamicamente. Eu também estava me perguntando se precisava desalocar todos os dados alocados na saída.

Eu decidi implementar a desalocação de qualquer maneira e descobri que o programa falhou durante a desalocação. Ao analisar a falha, descobri um erro na implementação da estrutura de dados e algoritmos principais (um vazamento de memória).

As lições que aprendi foram:

  1. Sempre implemente a desalocação para os dados alocados, o que os torna mais reutilizáveis caso você queira incorporar seu código em um sistema maior.
  2. A desalocação pode servir como uma verificação adicional de que seus dados alocados estão em um estado consistente quando são lançados.

Apenas meus 2 centavos.

EDITAR

Pequenos esclarecimentos: É claro que toda a memória alocada para um processo é liberada quando o processo é finalizado, portanto, se o único requisito é liberar a memória alocada, fazê-lo explicitamente é, na verdade, uma perda de tempo.

    
por 21.04.2012 / 14:30
fonte
12

Sempre liberte seus recursos. Libertar todos os seus recursos é importante porque é a única maneira de detectar efetivamente vazamentos. Para o projeto em que estou trabalhando, tenho até wrappers em torno de malloc / realloc / free para inserir canários, acompanhar estatísticas, etc; simplesmente para detectar problemas mais cedo.

No entanto, com exceção da detecção de vazamentos, para recursos liberados na saída (não antes), é um desperdício de tempo. O sistema operacional deve ser capaz de liberá-lo (por exemplo, caso o processo falhe, ou até mesmo liberar memória RAM usada para o código do processo); e o sistema operacional deve ser capaz de liberá-lo mais rapidamente do que o espaço do usuário, porque o kernel fará "atacado" em vez de "fragmentado", e haverá menos transições entre o kernel e o processo envolvido.

Felizmente você não precisa escolher de um jeito ou de outro. Se você quiser ter certeza de que seu código está correto (e precisa), mas também quer o melhor desempenho possível, faça algo como:

#ifndef FAST_EXIT
    free(stuff);
#endif
    
por 20.03.2012 / 04:11
fonte
8

A rotina de limpeza pode ser útil se você fizer isso periodicamente para recuperar espaço, ou para provar que é capaz de recuperar exatamente tantos nós quanto alocados, para verificar se não há vazamentos de memória. Mas como o serviço de limpeza imediatamente antes do processo morrer, não faz sentido, já que o sistema operacional recupera o controle de toda a arena da memória naquele instante.

    
por 19.03.2012 / 15:59
fonte
4

Will there be a different behavior later?

Há uma questão crítica relacionada a essa pergunta que você precisa fazer:

Alguém já usará esse código novamente por algum motivo?

Se a resposta poderia ser sim, se o código é usado sozinho ou como parte de um sistema maior, você criou uma mina terrestre com vazamento de memória monumental para a próxima pessoa a pisar.

É muito difícil lembrar, durante o curso, que você está aprendendo como fazer software que outras pessoas usarão incluindo o futuro (em vez de apenas resolver o problema do dia) . Isso significa que você precisa obedecer a certos comportamentos básicos de programação, incluindo: devolver os recursos quando terminar com eles.

    
por 20.03.2012 / 14:23
fonte
2

Se você implementar seu próprio tipo de dados "lista vinculada" não escrevendo uma rotina de limpeza / desconstrutor, terá mais dores de cabeça a longo prazo do que você imagina.

Sem código de limpeza, reutilizar o que você escreveu será muito mais difícil, pois seu tipo não pode ser usado sem cuidado especial (por exemplo, nunca criá-los em uma função ou loop, mas de preferência exclusivamente em main ).

Faça um favor a si mesmo e a todos e escreva-lhe list_cleanup ou ~List .

    
por 20.03.2012 / 10:59
fonte
1

Em sistemas multiusuários, o sistema operacional sempre liberará esses recursos, pois seria um risco de segurança se não o fizesse. O conteúdo da sua memória pode acabar no processo de outra pessoa!

    
por 19.03.2012 / 15:58
fonte
1

As rotinas de limpeza podem ter erros como qualquer outro código. Uma visão triste é um programa que faz o que você quer, exceto que ele trava ou falha na saída. A prática geral é ter o código limpo após ele mesmo, mas a limpeza de memória na saída do processo é um caso em que você não precisa.

    
por 19.03.2012 / 17:48
fonte
1

Quase sempre sim. Semáforos de memória compartilhada e recursos do servidor UDP (o sistema operacional não sabe como notificar os servidores UDP conectados que você acabou de fazer).

    
por 19.03.2012 / 19:19
fonte
1

Eu sempre limpo recursos na saída normal. É uma verificação de segurança de que minhas chamadas de alocação / desalocação de recursos são feitas corretamente. Esta verificação me alertou sobre bugs ocultos em mais de uma ocasião. É como equilibrar os livros de uma empresa no final do dia.

Pode haver casos extremos como o @MSalter descrito em seu comentário, mas mesmo isso geralmente me levaria a um gerenciamento de memória personalizado, em vez de apenas deixar o sistema operacional limpo e esperar pelo melhor.

    
por 19.03.2012 / 19:57
fonte
0

Se você tem 100% de certeza de que nenhum outro processo está referenciando sua lista vinculada e os nós, clique em OK.

100% é um número muito alto, no entanto. Sua lista foi referenciada por algum código de persistência que está sendo agrupado? Um componente de interface do usuário ainda tem um identificador nele? Qualquer coisa mais?

Vazamentos de memória geralmente não acontecem de propósito.

    
por 19.03.2012 / 16:44
fonte
0

O problema é que hoje é um nó de lista vinculada e, amanhã, é um recurso que o SO não pode limpar sozinho. É rápido e seguro deixar o sistema operacional para limpar a memória heap? Sim. Mas isso faz uma boa ideia? Não necessariamente.

    
por 19.03.2012 / 20:04
fonte
-1

Algumas bibliotecas de GUI do C ++ vazam recursos como este. Isso não é um julgamento de valor, mas vazar recursos e permitir que o sistema operacional os recupere é uma ocorrência comum em "código real".

É sempre uma boa prática limpar, você nunca sabe quando vai querer integrar essa ferramenta com outra coisa, e então o trabalho já está feito (ao invés de entrar na máquina de recordar / lembrar e lembrar de todos os pontos você vazou intencionalmente).

Em um caso, encontramos um bug porque a desalocação estava causando uma falha, porque algum outro bug de memória substituiu o cabeçalho que o delete usa. Então, às vezes, ele pode ajudá-lo a encontrar bugs em outras áreas para liberar todos os seus recursos (você pode encontrar uma superação no bloco anterior).

    
por 23.03.2012 / 02:28
fonte
-2

O gerenciamento de memória é a melhor prática, enquanto tomar decisões para liberá-la em um contexto é a otimização!

Agora a bola está no nosso campo!

    
por 23.03.2012 / 05:44
fonte
-2

Uma coisa para pensar:

Se o seu código estiver em uma DLL, você deve limpar com certeza, caso contrário, assumindo que a saída do processo liberará os recursos, a DLL não será recarregável.

    
por 04.04.2012 / 15:41
fonte