Sistemas Operacionais Modernos: Processos - Parte I

Definição

Os processos são considerados um conceito fundamental na computação. Para uma definição mais didática: “Um processo é, basicamente, um programa em execução […] na essência, um contêiner que armazena todas as informações necessárias para executar um programa” (TANEMBAUM, 2023).

Em outros critérios, os processos são instâncias dinâmicas de programas em execução. Isto é: uma vez que programas computacionais são um conjunto de instruções ordenadas para a realização de tarefas, os processos são as instâncias realizadoras destas instruções. Desta forma, um programa pode possuir um ou mais processos atrelados a si.

Caso você esteja utilizando um sistema GNU/Linux, você pode visualizar os processos que estão sendo executados neste exato momento, utilizando o comando ps aux:

Isolamento de Processos

Atualmente, os processos de um sistema operacional moderno são executados em ambientes isolados em múltiplos aspectos. Ou seja:

  • São identificados por um PID (Process ID) único, associados a um grupo ou usuário do sistema (ex.: PID “6582”). Em sistemas GNU/Linux, é possível obter o PID de um processo utilizando o comando pidof <nome-do-processo>. A mérito de exemplo, o processo principal e os subprocessos do firefox:
  • Possuem seu próprio espaço de endereçamento virtual (onde o processo “enxerga” a memória como se fosse exclusiva).
  • Dispõem de recursos do sistema próprios (File descriptors, Handles, Permissões de Acesso, Portas de Rede, etc).
  • Não acessam o hardware diretamente: para isso, utilizam chamadas de sistema (systemcalls) direcionadas ao Kernel.
  • Possuem recursos de IO (Input/Output) segregados (ex.: arquivos e dispositivos como teclados, mouse, etc).

Como provavelmente já é possível notar, o motivo da criação do isolamento de processos tem a ver com questões de segurança.

Sistemas antigos, como o MS-DOS, executavam apenas um processo por vez, portanto, não havia qualquer necessidade na execução isolada desses processos, pois não haviam riscos de um processo interferir na execução de outro.

No entanto, com o advento de sistemas operacionais “multitask” atuais, em que são executados diversos processos “ao mesmo tempo” (isto é: compartilham um mesmo processador - CPU - e demais recursos), por meio de comutação¹, foi necessária a implementação desses ambientes isolados para cada processo.

A importância disso é simples: imagine, por exemplo, se um processo em execução realiza uma operação de escrita em uma região de memória pertencente a outro processo? As consequências disso podem variar de comportamentos indefinidos (“undefined behaviors”) e deadlocks, a crashes gerais de sistema.

Componentes de um Processo

Os processos possuem alguns componentes que definem suas estruturas e comportamentos:

Program Code (“Text Session”)
  • Contém as instruções em código de máquina compiladas do programa.
  • É apenas leitura (read-only) e pode ser compartilhado entre várias instâncias do mesmo processo.
  • Representa a lógica estática do programa (algoritmos, funções, etc.).
Data Section
  • Armazena variáveis globais e estáticas (ex.: static int x em C).
  • Divide-se em:
    • Dados inicializados (valores pré-definidos, como int y = 10;).
    • Dados não inicializados (valores zerados ou indefinidos até a execução).
  • Funciona como uma área de armazenamento persistente durante a vida do programa.
Pilha (Stack)
  • Gerencia o mecanismo de chamadas de funções.
  • Armazena:
    • Variáveis locais.
    • Parâmetros de funções.
    • Endereços de retorno (para onde voltar após uma função).
  • Cresce e diminui dinamicamente durante a execução (alocação automática).
Heap (Área de Alocação Dinâmica)
  • Responsável por alocação de memória em tempo de execução (ex.: malloc() em C).
  • Requer gerenciamento manual (em linguagens como C/C++) ou automático (como em linguagens de alto nível Java/Python).
  • Oferece flexibilidade para estruturas de dados dinâmicas (listas, árvores, etc.).

Estrutura de Memória de um Processo

High Memory Address
+---------------------------------------------------+
|         Kernel Virtual Address Space              |
|                                                   |
|   ◆ Kernel code, data, and modules                |
|   ◆ Shared across all processes                   |
+---------------------------------------------------+
|                     Stack                         |
|   ◆ Dynamic memory for function calls             |
|   ◆ Local variables                               |
|   ◆ Grows downward ↓                              |
+---------------------------------------------------+
|                     Heap                          |
|   ◆ Dynamic memory allocation                     |
|   ◆ malloc(), new()                               |
|   ◆ Grows upward ↑                                |
+---------------------------------------------------+
|             Uninitialized Data                    |
|   ◆ BSS segment                                   |
|   ◆ Zero-initialized static variables             |
+---------------------------------------------------+
|               Initialized Data                    |
|   ◆ Data segment                                  |
|   ◆ Initialized global and static variables       |
+---------------------------------------------------+
|                 Program Text                      |
|   ◆ Text segment                                  |
|   ◆ Executable instructions                       |
|   ◆ Read-only memory                              |
+---------------------------------------------------+
|                  Kernel Space                     |
|   ◆ Per-process kernel data structures            |
|   ◆ Page tables                                   |
+---------------------------------------------------+
|               Kernel Direct Mapping               |
|   ◆ Direct mapping of all physical memory         |
+---------------------------------------------------+
|              Kernel Dynamic Memory                |
|   ◆ Memory for kernel modules                     |
|   ◆ vmalloc() allocation                          |
+---------------------------------------------------+
Low Memory Address

Estados de Processos

Um processo pode transitar por diversos estados durante sua execução:

  1. New: O processo está em fase de criação.
  2. Ready: Preparado para execução, no aguardo de alocação de CPU.
  3. Running: Executando as instruções do programa.
  4. Waiting: Em pausa. Aguardando eventos externos (Inputs/Outputs).
  5. Terminated: Execução completa. Recursos sendo desalocados.

Para visualizar os estados de um processo do tipo service, em sistemas GNU/Linux que utilizam systemd, é possível utilizar o comando systemctl status <nome-do-processo>.

Espero que este post tenha te auxiliado, de alguma forma, a ter uma melhor compreensão sobre processos em Sistemas Operacionais Modernos. Na Parte II desta linha sobre Processos, entraremos em maiores detalhes, como por exemplo, dos diferentes tipos de processos: services, daemons, etc. Além disso, vamos abordar o conceito de “inter-process communication”.

Quaisquer dúvidas, críticas ou sugestões, basta enviar um e-mail para: [email protected].


¹: "… a computação multitarefa permite que cada processador comute entre tarefas que estão sendo executadas sem ter que esperar que cada tarefa finalize. Dependendo da implementação do sistema operacional, a comutação pode ser realizada quando tarefas realizam operações de entrada/saída, quando uma tarefa indica que ela pode ser comutada, ou quando há interrupções de hardware."


REFERÊNCIA BIBLIOGRÁFICA

TANEMBAUM, Andrew S., Sistemas Operacionais Modernos. 5. ed. Porto Alegre: Bookman, 2023. 27 p.

Postado por: bl4nk_

$whoami:

bl4nk_: Analista DevOps com foco em K8S e estudos em segurança. Escritor nas horas vagas.


2025-07-24