Ao interromper um processo, ocorre um vazamento de memória?

6

Digamos que eu criei um programa em c / c ++, onde aloquei manualmente algumas variáveis. Então, durante a execução do programa, envio um sinal de interrupção (Ctrl-C). Essas variáveis são liberadas da memória ou elas ocuparão espaço até que o sistema seja desligado?

Além disso, e se eu acabei de criar números inteiros que não foram alocados manualmente, essas variáveis residem ou elas são excluídas imediatamente?

Estou pensando que as variáveis alocadas permanecerão e as variáveis regulares serão excluídas (por causa da pilha). Se for esse o caso, existe alguma maneira de liberar as variáveis alocadas da memória após o programa ter parado?

Apenas curioso. :)

    
por alanxoc3 08.04.2016 / 18:04

3 respostas

8

Os processos são gerenciados pelo kernel. O kernel não se importa como o programador aloca variáveis. Tudo o que se sabe é que certos blocos de memória pertencem ao processo. O tempo de execução C combina os recursos de gerenciamento de memória C com os recursos do kernel: variáveis automáticas entram em um bloco de memória chamado “stack” e o armazenamento dinâmico ( malloc e amigos) entra em um bloco de memória chamado “heap”. O processo chama as chamadas do sistema, como sbrk e mmap para obter memória com uma granularidade de páginas MMU . Dentro desses blocos, o tempo de execução determina onde colocar variáveis automáticas e objetos alocados dinamicamente.

Quando um processo é interrompido, o kernel atualiza sua tabela de gerenciamento de memória para registrar, para cada página da MMU, que ele não está mais em uso pelo processo. Isso ocorre independentemente de como o processo ocorre, seja de sua própria violação (chamando uma chamada de sistema) ou não (morto por um sinal). As páginas que não são mais usadas por nenhum processo são marcadas como reutilizáveis.

Geralmente é uma boa higiene liberar o armazenamento alocado dinamicamente que você não está mais usando, porque você nunca sabe quando um pedaço de código pode ser reutilizado em um programa de longa duração. Mas quando um processo morre, o sistema operacional libera todos os seus recursos: memória, arquivo aberto, etc.

Os únicos recursos que o sistema operacional não limpa automaticamente são recursos projetados para ter um escopo global no sistema operacional, como arquivos temporários.

    
por 09.04.2016 / 03:56
2

Sempre que um processo sai normalmente ou através de SIGINT , SIGTERM , SIGKILL etc, a chamada do sistema exit é invocada. Parte do trabalho da chamada exit é recuperar todos os recursos que estavam sendo usados pelo processo.
Essencialmente, sempre que o SO vê um status de saída (sucesso ou não) sendo retornado, duas coisas acontecem:

  1. SIGCHLD é enviado para o processo pai para permitir que os pais saibam que a criança morreu
  2. Chamada do sistema exit é chamada, o que limpará os recursos usados pelo processo que acabou de morrer

Mesmo para processos zumbis e órfãos, o SO atribui um processo especial para capturar o código de saída a partir deles e, em seguida, invoca exit system call.

No entanto, isso não significa que você pode usar o free() em seu código. Se você não fizer isso, você vai inchar os requisitos de memória para o seu software, o que pode, por sua vez, retardar todo o sistema. Qualquer coisa que não seja mais necessária deve ser liberada.

    
por 08.04.2016 / 19:37
-2

Se determinados bits de memória precisam ser zerados (por exemplo, uma senha ou chave privada), você precisará de um manipulador de sinal que chame memset(3) ou o que quer que seja antes do processo se mostrar pela porta. Veja também libsodium , que possui algumas rotinas úteis e portáveis relevantes para isso: sodium_mlock , sodium_memzero , etc. Sempre zerando toda a memória após cada saída de processo poderia ser feita pelo kernel, embora sem dúvida diminuísse o sistema.

A memória usada anteriormente (mas possivelmente não zerada) será reutilizada pelo kernel, se necessário; programadores de idiomas que oferecem alocação de memória manual devem estar cientes de que suas estruturas de dados podem conter quem sabe o que de algum programa anterior (o sinalizador do compilador -Wuninitialized é relevante aqui).

E quanto à afirmação de StephenKitt de que todas as alocações são sempre zeradas, bem, eu acho que você poderia escrever código nessa suposição.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
    int i, blahblah[1000000];
    for (i = 0; i < 1000000; i++) {
      if (blahblah[i] != 0) {
          printf("whoops, %d at %d ain't zero\n", blahblah[i], i);
      }
    }
    exit(EXIT_SUCCESS);
}
    
por 08.04.2016 / 19:36