quarta-feira, 22 de fevereiro de 2012

Processo x Programa Executável

"Alguém sabe a diferença entre um Processo e um Programa Executável?"

Esta foi a pergunta que um amigo, o Sergio Prallon, fez em uma turma de amigos para a qual ele ensinava C, a qual eu entrei de penetra. E eu respondi da seguinte forma:

"Processo é o programa em execução, e o Programa Executável são os dados necessários para criar um Processo."

É uma resposta curta e simples para algo que é um pouco mais complexo se for ver os detalhes.

Um processo costumava ter, no mínimo, 6 áreas em memória, naquela época. Atualmente deve ter mais uma, pelo menos, que são as bibliotecas compartilhadas, que sempre ficam carregadas em memória, e que todos os programas em execução podem usar.

Um programa fonte é compilado, traduzido, para um Código Objeto Realocável, que no Unix costuma ter a extensão ".o". Depois um Link Editor junta ele a outros Códigos Objetos Realocáveis que estão na biblioteca (que contém as funções que o programador usa, como printf(), strlen() etc, e mais um bando de coisas), e coloca o código de inicialização, gerando assim o Arquivo Objeto Executável, também chamado de Programa Executável.

O Programa Executável contém:
  • Cabeçalho descrevendo alguns detalhes dele, e o endereço inicial  de execução, por onde deve começar a ser executado;
  • O código do programa em uma área chamada de text;
  • As variáveis estáticas, criadas a tempo de compilação, que tem um valor inicial, em uma área chamada de data;
  • Também no cabeçalho tem o tamanho de uma área chamada de BSS, que conterá as variáveis estáticas que não foram inicializadas, e talvez também as inicializadas com zero. Quando o programa é carregado para a memória, para a formação da imagem do processo em memória, é reservada esta área, logo após a área data, e ela é limpa, zerada.
O text continua se chamando de text em memória, na imagem do processo, tal como a data e a BSS, mas surgem algumas novas áreas em memória:
  • A heap, que começa depois da BSS e cresce para cima, conforme é pedida mais memória ao sistema operacional. Quem faz este pedido, se não achou um espaço reaproveitável na heap, é a função malloc() e suas irmãs;
  • Um vazio, que não é mapeado. Não existe realmente memória acessível neste espaço, e se houver uma tentativa de acesso a este espaço, ocorrerá o erro segmentation violation;
  • E a pilha, stack, que começa no topo e cresce de cima para baixo. Antigamente, nos processadores de 16 bits, existia a chance de colisão entre a stack e a heap, mas atualmente, com o mapeamento de memória maior que a memória física existente, um programa é abortado por falta de memória de swap, ou algum outro evento, antes que isto aconteça.
Uma curiosidade é que, como a área de text de um processo é imutável, uma vez carregada para a memória ela não pode ser mais modificada, se existirem vários processos que foram originados do mesmo Programa Executável, todos eles podem usar uma só área de text, economizando globalmente a memória em um sistema.

Alguns compiladores, como o gcc, colocam strings constantes - como o primeiro parâmetro da printf(), que define a formatação de saída - na área de text. Como ela não deve mudar mesmo, não precisa estar na data, que admite alteração (Sob uma opção de compilação, este comportamento pode ser alterado.). A vantagem é que é mais coisa que fica na área de text para ser compartilhada entre processos, economizando mais memória.

Neste ponto já é possível explicar como são alocadas variáveis em memória, especialmente as static, mas isto fica para outro texto.

Nenhum comentário:

Postar um comentário