Digamos que eu tenha o seguinte código C:
int main () {
int *p = malloc(10 * sizeof *p);
*p = 42;
return 0; //Exiting without freeing the allocated memory
}
Quando eu compilar e executar esse programa C, ou seja, depois de alocar algum espaço na memória, essa memória que aloquei ainda estará alocada (ou seja, basicamente ocupando espaço) após eu sair do aplicativo e o processo terminar?
c
memory-management
Andreas Grech
fonte
fonte
Respostas:
Depende do sistema operacional. A maioria dos sistemas operacionais modernos (e todos os principais) liberarão memória não liberada pelo programa quando ele terminar.
Confiar nisso é uma prática ruim e é melhor liberá-lo explicitamente. O problema não é apenas que seu código parece ruim. Você pode decidir que deseja integrar seu pequeno programa a um maior e de longa duração. Então, um pouco mais tarde, você terá que passar horas rastreando vazamentos de memória.
Depender de um recurso de um sistema operacional também torna o código menos portátil.
fonte
Em geral, os sistemas operacionais modernos de uso geral são limpos após processos encerrados . Isso é necessário porque a alternativa é o sistema perder recursos com o tempo e exigir a reinicialização devido a programas que são mal escritos ou simplesmente têm bugs que raramente ocorrem e vazam recursos.
Ter seu programa liberando explicitamente seus recursos de qualquer maneira pode ser uma boa prática por vários motivos, como:
No entanto, aqui está um motivo para pular a liberação de memória: desligamento eficiente . Por exemplo, suponha que seu aplicativo contenha um grande cache na memória. Se, ao sair, passar por toda a estrutura do cache e o liberar um pedaço de cada vez, isso não terá nenhuma utilidade e desperdiçará recursos. Especialmente, considere o caso em que as páginas de memória contendo seu cache foram trocadas para o disco pelo sistema operacional; percorrendo a estrutura e liberando-a, você está trazendo todas essas páginas de volta à memória de uma vez , desperdiçando tempo e energia significativos sem nenhum benefício real e possivelmente até fazendo com que outros programas no sistema sejam trocados!
Como exemplo relacionado, existem servidores de alto desempenho que funcionam criando um processo para cada solicitação e, em seguida, fazendo com que ele seja encerrado quando concluído; dessa forma, eles nem mesmo precisam rastrear a alocação de memória e nunca fazem nenhuma liberação ou coleta de lixo, uma vez que tudo simplesmente desaparece na memória livre do sistema operacional no final do processo. (O mesmo tipo de coisa pode ser feito dentro de um processo usando um alocador de memória personalizado, mas requer uma programação muito cuidadosa; essencialmente, fazer a própria noção de "processos leves" dentro do processo do sistema operacional.)
fonte
Minhas desculpas por postar tanto tempo após a última postagem neste tópico.
Um ponto adicional. Nem todos os programas chegam a saídas elegantes. Falhas e ctrl-Cs, etc. farão com que o programa seja encerrado de maneiras não controladas. Se seu sistema operacional não liberasse seu heap, limpe sua pilha, exclua variáveis estáticas, etc, você eventualmente travaria seu sistema por vazamentos de memória ou coisa pior.
Além disso, o interessante é que trava / quebra no Ubuntu, e eu suspeito que todos os outros sistemas operacionais modernos, têm problemas com recursos "controlados". Sockets, arquivos, dispositivos, etc. podem permanecer "abertos" quando um programa termina / trava. também é uma boa prática fechar qualquer coisa com um "identificador" ou "descritor" como parte de sua limpeza antes da saída normal.
Atualmente, estou desenvolvendo um programa que usa muito soquetes. Quando eu fico preso em um travamento, tenho que ctrl-c para fora dele, assim, encalhando meus soquetes. Eu adicionei um std :: vector para coletar uma lista de todos os sockets abertos e um manipulador de sigaction que captura sigint e sigterm. O manipulador percorre a lista e fecha os soquetes. Estou pensando em fazer uma rotina de limpeza semelhante para usar antes de lançar, que levará ao encerramento prematuro.
Alguém se importa em comentar sobre este design?
fonte
O que está acontecendo aqui ( em um sistema operacional moderno ), é que seu programa é executado dentro de seu próprio "processo". Esta é uma entidade de sistema operacional dotada de seu próprio espaço de endereço, descritores de arquivo, etc. Suas
malloc
chamadas estão alocando memória do "heap" ou páginas de memória não alocadas que são atribuídas ao seu processo.Quando seu programa termina, como neste exemplo, todos os recursos atribuídos ao seu processo são simplesmente reciclados / destruídos pelo sistema operacional. No caso da memória, todas as páginas de memória atribuídas a você são simplesmente marcadas como "livres" e recicladas para o uso de outros processos. As páginas são um conceito de nível inferior do que o que malloc manipula - como resultado, as especificações de malloc / free são simplesmente apagadas conforme a coisa toda é limpa.
É o equivalente moral de, quando você termina de usar seu laptop e quer dá-lo a um amigo, não se preocupa em excluir cada arquivo individualmente. Você acabou de formatar o disco rígido.
Dito isso, como todos os outros respondentes estão observando, confiar nisso não é uma boa prática:
fonte
Sim. O sistema operacional limpa os recursos. Bem ... as versões antigas do NetWare não.
Edit: Como San Jacinto apontou, certamente existem sistemas (além do NetWare) que não fazem isso. Mesmo em programas descartáveis, tento criar o hábito de liberar todos os recursos apenas para manter o hábito.
fonte
Sim, o sistema operacional libera toda a memória quando o processo termina.
fonte
malloc
só posso prometer o que C fará com a memória; por design, C não garante muito em relação ao comportamento fora do próprio C. Se o aplicativo morrer inesperadamente, qualquer promessa feita pela biblioteca de tempo de execução será nula e sem efeito, uma vez que ela não está mais viva para cumpri-la.Depende, os sistemas operacionais geralmente limparão para você, mas se você estiver trabalhando, por exemplo, em um software integrado, ele pode não ser lançado.
Apenas certifique-se de liberá-lo, ele pode economizar muito tempo depois, quando você quiser integrá-lo a um grande projeto.
fonte
Isso realmente depende do sistema operacional, mas para todos os sistemas operacionais que você encontrar, a alocação de memória desaparecerá quando o processo for encerrado.
fonte
Acho que a liberação direta é melhor. Comportamento indefinido é a pior coisa, então se você tiver acesso enquanto ele ainda está definido em seu processo, faça-o, pois existem muitos bons motivos que as pessoas deram para isso.
Quanto a onde, ou se, descobri que em W98, a verdadeira questão era 'quando' (não vi uma postagem enfatizando isso). Um pequeno programa de modelo (para entrada MIDI SysEx, usando vários espaços malloc) iria liberar memória no bit WM_DESTROY do WndProc, mas quando eu transplantei isso para um programa maior, ele travou ao sair. Presumi que isso significava que estava tentando liberar o que o sistema operacional já havia liberado durante uma limpeza maior. Se eu fizesse isso em WM_CLOSE e depois chamasse DestroyWindow (), tudo funcionaria bem, saída limpa instantânea.
Embora não seja exatamente o mesmo que os buffers de MIDI, há semelhanças no fato de que é melhor manter o processo intacto, limpar totalmente e depois sair. Com pedaços de memória modestos, isso é muito rápido. Descobri que muitos buffers pequenos trabalharam mais rápido na operação e limpeza do que menos grandes.
Exceções podem existir, como alguém disse ao evitar puxar grandes pedaços de memória de um arquivo de troca no disco, mas mesmo isso pode ser minimizado mantendo mais e menores espaços alocados.
fonte