# 7. BEAM (Bogdan Erlang Abstract Machine)

### 📋 ÍNDICE

1. Visão Geral da BEAM
2. Arquitetura da BEAM
3. Processos na BEAM
4. Escalonamento e Concorrência
5. Gerenciamento de Memória
6. Tolerância a Falhas
7. Código Quente (Hot Code Swapping)
8. BEAM vs Outras VMs
9. Otimizações da BEAM
10. Ferramentas de Observabilidade
11. Considerações de Performance
12. Resumo Técnico
13. Referência Rápida

***

### 1. VISÃO GERAL DA BEAM

A **BEAM** (Bogdan's Erlang Abstract Machine) é a máquina virtual que executa o código compilado de linguagens como **Elixir**, **Erlang** e **Gleam**. Ela faz parte do sistema operacional de tempo de execução conhecido como **ERTS** (Erlang Runtime System).

Diferente de máquinas virtuais como a JVM (Java), a BEAM foi projetada especificamente para sistemas de alta disponibilidade, distribuídos e com tolerância zero a falhas.

#### Principais Pilares da BEAM

* **Modelo de Atores e Processos Leves:** Na BEAM, tudo é um processo. Esses processos não são processos do sistema operacional, mas sim entidades extremamente leves gerenciadas pela própria VM. É possível rodar milhões de processos simultâneos em uma única máquina com baixo consumo de memória.
* **Isolamento Total:** Cada processo possui sua própria memória (heap e stack). Se um processo falha ou sofre um "crash", ele não afeta os outros. Isso permite a filosofia de design **"Let it crash"** (Deixe quebrar), onde supervisores reiniciam partes específicas do sistema de forma automática.
* **Agendamento Preemptivo (Preemptive Scheduling):** A VM garante que nenhum processo "monopolize" a CPU. Ela alterna rapidamente entre os processos em execução, garantindo uma latência previsível e baixa, o que é essencial para sistemas de chat, jogos online ou transações financeiras.
* **Distribuição Nativa:** A BEAM permite que processos se comuniquem da mesma forma, estejam eles rodando na mesma CPU ou em servidores diferentes em lados opostos do mundo. A rede é tratada de forma transparente pelo sistema.

#### Por que ela é importante para o Elixir?

Embora o Elixir tenha uma sintaxe moderna e amigável, todo o seu poder de concorrência e estabilidade vem diretamente da BEAM. Ao escrever Elixir, você está, na verdade, aproveitando décadas de engenharia de sistemas de telecomunicações (herança do Erlang) para construir aplicações web escaláveis e resilientes.

```yaml
BEAM - CARACTERÍSTICAS FUNDAMENTAIS:

  🎯 PROPÓSITO:
    - Máquina virtual otimizada para concorrência
    - Desenvolvida originalmente para a Ericsson
    - Projetada para sistemas de telefonia (uptime de 9 noves)
    - Nomeada em homenagem a Bogumil "Bogdan" Hausman
  
  🔑 DIFERENCIAIS COMPETITIVOS:
    - Processos: ~2-3KB por processo (vs MB em outras VMs)
    - Trocas de contexto: ~1-2 microssegundos
    - Escalonamento: O(1) por scheduler
    - Disponibilidade: 99.9999999% (nove noves)
    - Milhões de processos simultâneos
  
  📊 MÉTRICAS REAIS:
    - WhatsApp: 2B usuários com BEAM/Erlang
    - Discord: 5M+ conexões WebSocket simultâneas
    - Banco do Brasil: sistemas críticos com BEAM
```

***

### 2. ARQUITETURA DA BEAM

#### 2.1 Componentes Principais

```
VISÃO ESTRUTURAL DA BEAM

┌─────────────────────────────────────────────────────────────┐
│                    BEAM VIRTUAL MACHINE                     │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐   ┌──────────────┐   ┌──────────────────┐  │
│  │   LOADER    │   │  SCHEDULERS  │   │ MEMORY MANAGERS  │  │
│  │ (Bytecode)  │   │ (1 per Core) │   │ (Process Heaps)  │  │
│  └─────────────┘   └──────┬───────┘   └──────────────────┘  │
│                           │                                 │
│  ┌─────────────┐   ┌──────▼───────┐   ┌──────────────────┐  │
│  │  PROCESSES  │   │  RUN QUEUES  │   │    ETS TABLES    │  │
│  │ (Lightweight)   │ (Task Mgmt)  │   │ (Shared Memory)  │  │
│  └─────────────┘   └──────────────┘   └──────────────────┘  │
│                                                             │
│  ┌─────────────┐   ┌──────────────┐   ┌──────────────────┐  │
│  │    PORTS    │   │     NIFs     │   │      BIFs        │  │
│  │ (I/O Drivers)   │ (Native C)   │   │ (Built-in Funs)  │  │
│  └─────────────┘   └──────────────┘   └──────────────────┘  │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │           NET KERNEL (Node Distribution)              │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
```

#### 2.2 Funcionamento da BEAM

O fluxo de execução na BEAM segue um ciclo bem definido: o código fonte Elixir ou Erlang é compilado para bytecode BEAM, que é então carregado na VM. Quando uma função é chamada, a BEAM interpreta ou executa nativamente (via JIT) este bytecode, gerenciando memória, processos e mensagens.

```elixir
# 1. Código fonte Elixir/Erlang
defmodule Exemplo do
  def soma(a, b), do: a + b
end

# 2. Compilação para bytecode BEAM
# $ elixirc exemplo.ex

# 3. Carregamento na BEAM
Code.ensure_loaded(Exemplo)

# 4. Execução do bytecode
Exemplo.soma(1, 2)  # 3

# A BEAM executa instruções como:
# - move -> registradores virtuais
# - call -> funções
# - send -> mensagens entre processos
# - wait -> espera por eventos
```

#### 2.3 Registradores da BEAM

A BEAM utiliza um conjunto de registradores virtuais para executar o bytecode de forma eficiente. Estes registradores são otimizados para pattern matching, chamadas de função e gerenciamento de pilha.

| Registrador         | Descrição                       | Uso Típico                    |
| ------------------- | ------------------------------- | ----------------------------- |
| **X Registradores** | Argumentos e retorno de funções | X0, X1, X2... para parâmetros |
| **Y Registradores** | Variáveis locais na pilha       | Alocadas por frame de chamada |
| **Z Registradores** | Números de ponto flutuante      | Operações matemáticas         |
| **CP**              | Continuation Pointer            | Endereço de retorno           |
| **FCALL**           | Função de Call                  | Gerencia chamadas externas    |

***

### 3. PROCESSOS NA BEAM

#### 3.1 Estrutura de um Processo

Cada processo BEAM é uma entidade isolada que contém seu próprio Estado, Pilha de Execução, Heap de Dados, Fila de Mensagens e Contador de Reduções (unidade de trabalho). Esta estrutura é o que permite o isolamento total entre processos.

```
ESTRUTURA DE UM PROCESSO BEAM

┌─────────────────────────────────┐
│         PROCESS BLOCK           │
├─────────────────────────────────┤
│ • Process Control Block (PCB)   │ - ID, prioridade, status
│ • Stack (calls, returns)        │ - Pilha de execução
│ • Heap (dados do processo)      │ - Memória dinâmica
│ • Mailbox (fila de mensagens)   │ - Mensagens recebidas
│ • Generational Pointer          │ - Para GC
│ • Reductions counter            │ - Contador de reduções
└─────────────────────────────────┘
```

#### 3.2 Criação de Processos

Criar um processo na BEAM é extremamente leve. O exemplo abaixo mostra como criar um processo simples e obter informações detalhadas sobre seu consumo de memória e estado.

```elixir
# Criação de processo em Elixir
pid = spawn(fn ->
  # Código do processo
  # Cada processo tem sua própria heap/stack
  receive do
    msg -> IO.puts("Recebi: #{msg}")
  end
end)

# Informações do processo
Process.info(pid, :memory)        # Memória usada (bytes) - típico: ~2-3KB
Process.info(pid, :heap_size)     # Tamanho da heap
Process.info(pid, :stack_size)    # Tamanho da stack
Process.info(pid, :message_queue_len)  # Mensagens pendentes
Process.info(pid, :reductions)    # Reductions executadas
```

#### 3.3 Comunicação Entre Processos

Processos se comunicam através de **mensagens assíncronas**. Quando uma mensagem é enviada, ela é copiada para a mailbox do processo destino. Este modelo elimina a necessidade de locks ou memória compartilhada.

```elixir
# Mensagens são copiadas entre processos
pid = spawn(fn ->
  receive do
    {:msg, data} -> 
      # Processa a mensagem
      IO.puts("Processando: #{data}")
  end
end)

# Envio de mensagem (cópia)
send(pid, {:msg, "Hello"})

# Medição de performance de comunicação
defmodule Bench do
  def measure do
    parent = self()
    
    pid = spawn(fn ->
      receive do
        :start -> send(parent, :done)
      end
    end)
    
    start = System.monotonic_time()
    send(pid, :start)
    receive do
      :done -> :ok
    end
    elapsed = System.monotonic_time() - start
    
    IO.puts("Round-trip: #{elapsed} nanosegundos")
    # Típico: 1-5 microssegundos
  end
end
```

***

### 4. ESCALONAMENTO E CONCORRÊNCIA

#### 4.1 Escalonadores (Schedulers)

A BEAM utiliza um scheduler por core lógico disponível no sistema. Cada scheduler possui sua própria run queue (fila de processos prontos para execução). Este design permite escalabilidade linear em sistemas multi-core.

```
COMO FUNCIONA O ESCALONAMENTO NA BEAM

1. Cada scheduler roda em uma thread do SO
2. Cada scheduler tem sua própria run queue
3. Processos têm reductions (~2000 por time slice)
4. Escalonamento é PREEMPTIVO (não cooperativo)
5. Balanceamento dinâmico entre schedulers
```

```elixir
# Verificando schedulers disponíveis
System.schedulers()           # Número total de schedulers
System.schedulers_online()    # Schedulers ativos (tipicamente = cores)

# Opções de configuração da VM
# $ elixir --smp auto +S 4:4  # 4 schedulers, 4 online

# Informações detalhadas via Erlang
:erlang.system_info(:schedulers)
:erlang.system_info(:schedulers_online)
```

#### 4.2 Reductions (Fatias de Tempo)

Reductions são a unidade de medida de trabalho na BEAM. Cada operação básica consome um certo número de reductions. Quando um processo consome \~2000 reductions, ele é preemptado (interrompido) para que outro processo execute.

| Operação                  | Reductions Consumidas |
| ------------------------- | --------------------- |
| 1 chamada de função       | 1 reduction           |
| Pattern match simples     | 1 reduction           |
| Operação aritmética       | 2-3 reductions        |
| Envio de mensagem pequena | \~20 reductions       |
| Operações com ETS         | \~100 reductions      |

```elixir
defmodule ReductionCounter do
  def measure do
    parent = self()
    
    pid = spawn(fn ->
      # Loop infinito (cuidado!)
      loop(0)
    end)
    
    # Espera scheduler avançar
    Process.sleep(100)
    
    # Ver reductions usadas
    IO.inspect(Process.info(pid, :reductions))
    # Cada processo tem ~2000 reductions por vez
  end
  
  def loop(i) do
    # Cada iteração consome reductions
    loop(i + 1)
  end
end
```

#### 4.3 Run Queues e Balanceamento

As run queues são filas de processos prontos para execução. A BEAM automaticamente balanceia a carga entre schedulers, migrando processos quando necessário para manter todas as CPUs ocupadas.

```
ESTRUTURA DAS RUN QUEUES

SCHEDULER 1 → Run Queue [P1, P2, P3, ...]
SCHEDULER 2 → Run Queue [P4, P5, P6, ...]
SCHEDULER N → Run Queue [P7, P8, P9, ...]

BALANCEAMENTO:
- Migração automática de processos entre schedulers
- Load balancing dinâmico
- Colheita de processos dormindo (sleeping processes)
```

```elixir
# Monitorando run queues
:erlang.statistics(:run_queue)          # Total de processos aguardando
:erlang.statistics(:total_run_queue_lengths)

# Distribuição por scheduler
Enum.each(1..System.schedulers_online(), fn s ->
  qlen = :erlang.statistics(:run_queue_lengths) |> elem(s - 1)
  IO.puts("Scheduler #{s}: #{qlen} processos")
end)

# Ver processos por scheduler
Process.list()
|> Enum.group_by(fn pid -> 
    :erlang.process_info(pid, :scheduler_id) 
  end)
|> IO.inspect()
```

***

### 5. GERENCIAMENTO DE MEMÓRIA

#### 5.1 Coleta de Lixo por Processo

Uma das características mais inovadoras da BEAM é a coleta de lixo (GC) por processo. Cada processo tem seu próprio heap e coleta de lixo independente. Isso significa que quando um processo faz GC, toda a VM não precisa parar (evitando o problema "stop-the-world" comum em outras VMs).

```elixir
# GC é INDEPENDENTE por processo
defmodule GCExample do
  def create_memory_hungry_process do
    spawn(fn ->
      # Este processo tem sua própria heap
      big_list = Enum.to_list(1..1_000_000)
      
      # GC ocorre quando heap atinge limite
      # Não afeta outros processos!
      Process.sleep(:infinity)
    end)
  end
end

# Tipos de GC na BEAM
# Minor GC: Rápida, escaneia young generation
# Major GC: Mais lenta, escaneia toda heap (rara)
```

#### 5.2 Memória por Processo e Compartilhamento

Processos na BEAM são extremamente econômicos em memória (\~2-3KB iniciais). Além disso, termos imutáveis são compartilhados entre processos, evitando cópias desnecessárias de grandes estruturas de dados.

```elixir
# Processo pequeno (mínimo)
def minimal_process do
  pid = spawn(fn -> receive do: (-> :ok) end)
  IO.puts("Memória inicial: #{get_memory(pid)} bytes")
  # Típico: 2-3KB
  pid
end

def get_memory(pid) do
  Process.info(pid, :memory) |> elem(1)
end

# Compartilhamento de memória com termos imutáveis
def shared_memory do
  big_term = Enum.to_list(1..1_000_000)
  
  # Termos imutáveis são compartilhados, não copiados!
  p1 = spawn(fn -> keep(big_term) end)
  p2 = spawn(fn -> keep(big_term) end)
  
  # big_term NÃO é duplicado na memória
  {p1, p2}
end
```

#### 5.3 Tipos de Memória na BEAM

A BEAM gerencia diferentes tipos de memória com estratégias específicas para cada um:

| Tipo de Memória       | Descrição                     | Característica                        |
| --------------------- | ----------------------------- | ------------------------------------- |
| **Heap do Processo**  | Dados do processo             | GC por processo, crescimento dinâmico |
| **Stack do Processo** | Call frames, variáveis locais | Por processo, separada da heap        |
| **Message Queue**     | Mensagens pendentes           | Copiadas entre processos              |
| **ETS Memory**        | Tabelas compartilhadas        | Sem GC automático, acesso rápido      |
| **Code Area**         | Bytecode carregado            | Compartilhado entre processos         |
| **Binary Memory**     | Binários >64B                 | Reference counting, compartilhado     |

```elixir
# Monitorando memória total da BEAM
:erlang.memory(:total)        # Memória total
:erlang.memory(:processes)    # Memória dos processos
:erlang.memory(:ets)          # Memória de ETS
:erlang.memory(:binary)       # Memória de binários
:erlang.memory(:code)         # Memória de código
```

***

### 6. TOLERÂNCIA A FALHAS

#### 6.1 Modelo "Let It Crash"

A filosofia central da BEAM é "deixe quebrar" (let it crash). Em vez de tentar prever e prevenir todos os erros, a BEAM encoraja que processos falhem rapidamente e que supervisores sejam responsáveis por reiniciá-los em um estado conhecido e consistente.

```elixir
defmodule RobustProcess do
  use GenServer
  
  def start_link do
    GenServer.start_link(__MODULE__, nil, name: __MODULE__)
  end
  
  def risky_operation do
    GenServer.call(__MODULE__, :risky)
  end
  
  def init(_) do
    {:ok, %{attempts: 0}}
  end
  
  def handle_call(:risky, _from, state) do
    # Se falhar, supervisor reinicia
    result = do_risky_operation()
    {:reply, result, state}
  rescue
    e ->
      # Deixa o supervisor lidar (não tenta recuperar aqui!)
      {:stop, e, state}
  end
  
  defp do_risky_operation do
    # Algo que pode falhar
    1 / 0
  end
end

# Supervisor com estratégia de reinicialização
defmodule MySupervisor do
  use Supervisor
  
  def start_link do
    Supervisor.start_link(__MODULE__, [])
  end
  
  def init(_) do
    children = [
      {RobustProcess, []}
    ]
    
    # Estratégias de supervisão:
    # :one_for_one - reinicia só o que falhou
    # :one_for_all - reinicia todos
    # :rest_for_one - reinicia processo e seus dependentes
    Supervisor.init(children, strategy: :one_for_one)
  end
end
```

#### 6.2 Links e Monitores

**Links** criam uma relação bidirecional entre processos: se um morre, o outro também morre. **Monitores** são unidirecionais: o processo monitorado não é afetado, mas o monitor recebe uma notificação quando o alvo termina.

```elixir
# Links: comunicação bidirecional de falhas
def link_example do
  pid = spawn(fn -> 
    receive do
      :die -> exit(:kaboom)
    end
  end)
  
  # Link cria relação bidirecional
  Process.link(pid)
  
  # Quando pid morre, este processo também morre
  send(pid, :die)
end

# Monitores: monitoramento unidirecional (mais seguro)
def monitor_example do
  pid = spawn(fn -> 
    receive do
      :die -> exit(:normal)
    end
  end)
  
  # Monitor não afeta o processo monitorado
  ref = Process.monitor(pid)
  
  send(pid, :die)
  
  receive do
    {:DOWN, ^ref, :process, ^pid, reason} ->
      IO.puts("Processo morreu: #{reason}")
      # O processo atual continua vivo!
  end
end
```

***

### 7. CÓDIGO QUENTE (HOT CODE SWAPPING)

#### 7.1 Atualização de Código sem Parar

Uma das características mais impressionantes da BEAM é a capacidade de atualizar código em produção sem derrubar o sistema. Isso foi originalmente projetado para sistemas de telefonia que precisavam de 99.9999999% de uptime.

```elixir
# GenServer suporta código quente nativamente
defmodule HotSwapExample do
  use GenServer
  
  # Versão 1.0
  def handle_call(:version, _from, state) do
    {:reply, "1.0", state}
  end
  
  # Atualização de código (chamado automaticamente)
  def code_change(old_vsn, state, _extra) do
    # Transforma estado para nova versão
    new_state = case old_vsn do
      "1.0" -> Map.put(state, :new_field, "default")
      _ -> state
    end
    {:ok, new_state}
  end
end

# Como funciona na prática:
# 1. Compilar nova versão do módulo
# 2. Carregar na VM (l: modulo)
# 3. Processos existentes mantêm estado antigo
# 4. Novas chamadas usam novo código
# 5. Função code_change migra estado quando processo é atualizado
```

#### 7.2 Como Funciona o Hot Code Swapping

```
FLUXO DO HOT CODE SWAPPING NA BEAM

1. VM carrega nova versão do módulo (compilação)
2. Processos rodando código antigo continuam executando
3. Próximas chamadas de função usam nova versão
4. Estado é transformado via callback code_change
5. Processos podem ser atualizados individualmente

TIMELINE:
  t0: Módulo V1 carregado
  t1: Código atualizado para V2 (carregado na VM)
  t2: Processo P executa código V1 (estado antigo)
  t3: Processo P recebe atualização via :sys.change_code
  t4: code_change é chamada, transforma estado
  t5: Processo P agora executa código V2
```

***

### 8. BEAM vs OUTRAS VMs

#### 8.1 Comparação de Arquiteturas

A BEAM se destaca por seu modelo de concorrência único. Enquanto outras VMs usam threads pesadas ou event loops complexos, a BEAM oferece processos leves com isolamento total e escalonamento preemptivo.

| Característica                | BEAM (Elixir/Erlang)              | JVM (Java/Scala)       | V8 (Node.js)                | CPython            |
| ----------------------------- | --------------------------------- | ---------------------- | --------------------------- | ------------------ |
| **Modelo de Concorrência**    | Processos leves (atores)          | Threads OS             | Event Loop + Worker Threads | Threads OS + GIL   |
| **Custo por Processo/Thread** | \~2-3KB                           | \~1MB                  | \~4MB+                      | \~8MB+             |
| **Máx. concorrência típica**  | Milhões                           | Milhares               | Centenas                    | Centenas           |
| **Trocas de contexto**        | 1-2μs                             | \~10μs                 | N/A (single thread)         | \~15μs             |
| **Isolamento**                | Total (sem memória compartilhada) | Parcial (synchronized) | Parcial                     | Parcial (GIL)      |
| **Distribuição nativa**       | Sim                               | Bibliotecas            | Não                         | Não                |
| **Código quente**             | Sim                               | Limitado               | Não                         | Não                |
| **GC**                        | Por processo                      | Global (pausas)        | Global (pausas)             | Reference counting |

#### 8.2 Performance na Prática

```elixir
# Teste de concorrência: milhões de processos
defmodule ConcurrencyBench do
  def spawn_many(n) do
    1..n
    |> Enum.map(fn _ ->
      spawn(fn -> receive do: (_ -> :ok) end)
    end)
    |> Enum.count()
  end
  
  def measure do
    {time, count} = :timer.tc(fn -> spawn_many(1_000_000) end)
    IO.puts("#{count} processos criados em #{time / 1_000_000} segundos")
    # Resultado típico: 1M processos em < 2 segundos
    # Memória: ~2.5GB para 1M processos na BEAM
    # JVM/Node/Python: impossível criar 1M threads
  end
end
```

***

### 9. OTIMIZAÇÕES DA BEAM

#### 9.1 Tail Call Optimization (TCO)

A BEAM implementa otimização de chamada de cauda, permitindo recursão infinita sem estouro de pilha. Esta é uma característica fundamental para linguagens funcionais que usam recursão como estrutura de repetição principal.

```elixir
defmodule TailRecursion do
  # Com TCO - usa stack constante O(1)
  def sum(n, acc \\ 0)
  def sum(0, acc), do: acc
  def sum(n, acc), do: sum(n - 1, acc + n)
  # A última chamada é a própria função
  # → não há crescimento de pilha
  
  # Sem TCO - causa estouro de stack O(n)
  def bad_sum(0), do: 0
  def bad_sum(n), do: n + bad_sum(n - 1)
  # A última operação é '+' (não a chamada recursiva)
  # → pilha cresce linearmente com n
end

# Na prática, loops em Elixir são implementados com recursão de cauda
def process_large_list(list, acc \\ []) do
  case list do
    [] -> Enum.reverse(acc)
    [head | tail] -> process_large_list(tail, [transform(head) | acc])
  end
end
```

#### 9.2 Eficiência de Padrões

A ordem de eficiência das operações na BEAM segue uma hierarquia clara, e entender isso ajuda a escrever código mais performático.

| Operação                   | Complexidade         | Nota                     |
| -------------------------- | -------------------- | ------------------------ |
| Pattern matching           | O(1)                 | Mais rápido              |
| Acesso cabeça de lista     | O(1)                 | `[head \| tail]`         |
| Acesso por índice em lista | O(n)                 | Evitar em listas grandes |
| Envio de mensagens         | O(1) + cópia         | Custo da cópia do termo  |
| ETS operations             | O(1)                 | Tabelas hash             |
| Operações com binários     | O(1) para referência | Reference counting       |

```elixir
# Exemplo de pattern matching eficiente
def fast_match(list) do
  case list do
    [head | tail] -> process(head, tail)  # O(1)
    [] -> :empty
  end
end

# Operação menos eficiente
def slow_operation(list) do
  # List.delete é O(n) e cria nova lista
  new_list = List.delete(list, element)
  # List.to_tuple também é O(n)
  List.to_tuple(new_list)
end
```

#### 9.3 Binary Optimizations

Binários são uma das otimizações mais importantes da BEAM, especialmente para processamento de dados em rede, arquivos e protocolos.

```elixir
defmodule BinaryOpt do
  # Binary matching é extremamente eficiente
  def parse_header(<<size::32, type::8, rest::binary>>) do
    IO.puts("Size: #{size}, Type: #{type}")
    rest  # Retorna o restante sem cópia
  end
  
  # Construção de binários é otimizada
  def build_packet(id, data) do
    # BEAM aloca o binário exato de uma vez
    <<id::32, byte_size(data)::32, data::binary>>
  end
  
  # Reference counting para binários grandes
  def process_large_binary(bin) do
    # Binários > 64 bytes são reference counted
    # Compartilhados entre processos SEM cópia!
    p1 = spawn(fn -> handle(bin) end)
    p2 = spawn(fn -> handle(bin) end)
    p3 = spawn(fn -> handle(bin) end)
    # Os 3 processos compartilham a mesma referência
    # Nenhuma cópia extra de memória!
    {p1, p2, p3}
  end
  
  def handle(bin) do
    # Processa o binário sem copiar
    :ok
  end
end
```

***

### 10. FERRAMENTAS DE OBSERVABILIDADE

#### 10.1 Observer (GUI)

Observer é a ferramenta gráfica oficial para monitoramento de sistemas BEAM. Ela fornece uma visão em tempo real de todos os aspectos da VM, desde processos individuais até estatísticas globais de memória e CPU.

```elixir
# Iniciar Observer no IEx
:observer.start()

# O que Observer mostra:
"""
📊 SYSTEM OVERVIEW:
   - Utilização de CPU por scheduler
   - Memória total e por tipo
   - Load average e estatísticas
   - Conexões de rede

🔄 PROCESSES:
   - Lista completa de processos
   - Estado atual (running, waiting, etc)
   - Memória e reductions
   - Fila de mensagens

🌲 SUPERVISION TREES:
   - Árvore de supervisão completa
   - Relações entre processos
   - Estado dos supervisores

📈 LOAD CHARTS:
   - Histórico de uso de CPU
   - Alocação de memória
   - Run queue length

📝 SYSTEM LOGS:
   - Mensagens de sistema
   - Erros e warnings
"""
```

#### 10.2 Recon (CLI)

Recon é uma biblioteca de ferramentas CLI para debugging em produção, permitindo investigar problemas sem parar o sistema.

```elixir
# Adicionar recon ao mix.exs
defp deps do
  [{:recon, "~> 2.5"}]
end

# Uso no IEx (já em produção)
:recon.proc_count(10)              # Top 10 processos por memória
:recon.proc_count(:memory, 20)     # Top 20 por consumo de memória
:recon.proc_window("GenServer")    # Filtra processos por nome
:recon.proc_attrs(pid)              # Atributos detalhados do processo

# Análise de memória
:recon_alloc.memory(:allocated_types)  # Alocação por tipo
:recon_alloc.memory(:used_types)       # Uso atual por tipo

# Análise de deadlock/processos suspeitos
:recon_process.suspect(:most_used)     # Processos mais suspeitos
:recon_process.suspect(:highest_priority)  # Prioridade mais alta
```

***

### 11. CONSIDERAÇÕES DE PERFORMANCE

#### 11.1 Quando a BEAM é Mais Rápida

A BEAM não é a melhor escolha para todos os cenários. Entender seus pontos fortes e fracos é fundamental para arquitetar sistemas eficientes.

```
BENCHMARKS TÍPICOS - ONDE A BEAM SE DESTACA

✅ MELHOR NA BEAM:
  - Concorrência massiva: milhões de processos simultâneos
  - Operações I/O bound: rede, banco de dados, arquivos
  - Message passing: comunicação entre componentes
  - Pattern matching em estruturas complexas
  - Sistemas que precisam de tolerância a falhas
  - Aplicações distribuídas nativamente
  - WebSockets e conexões persistentes

❌ PIOR NA BEAM:
  - CPU intensivo puro: cálculos matemáticos pesados
  - Números de ponto flutuante em larga escala
  - Criptografia intensiva (use NIFs quando necessário)
  - Manipulação repetida de binários muito grandes
  - Processamento de imagens/vídeo
  - Machine learning training (inferência pode ser ok)
```

#### 11.2 Boas Práticas

```elixir
defmodule PerformanceTips do
  # ✅ Use tail recursion para loops longos
  def process_batch([], acc), do: acc
  def process_batch([head | tail], acc) do
    # Processa cada item sem crescimento de pilha
    process_batch(tail, [transform(head) | acc])
  end
  
  # ✅ Use binários grandes como referências compartilhadas
  def send_binary_to_many(pids, data) do
    Enum.each(pids, fn pid ->
      # Binários >64B são apenas referências
      send(pid, {:data, data})
    end)
  end
  
  # ✅ Use ETS para estado compartilhado entre processos
  @table __MODULE__
  def init_shared_table do
    :ets.new(@table, [:set, :named_table, :public])
  end
  
  # ✅ Use pool de processos (Task.Supervisor) para tasks
  def process_with_pool(items) do
    Task.Supervisor.start_link(name: MyPool)
    
    items
    |> Task.async_stream(&heavy_work/1, 
         max_concurrency: System.schedulers_online())
    |> Enum.to_list()
  end
end
```

#### 11.3 Evitando Armadilhas

```elixir
# ❌ Evite processamento pesado no processo principal
def bad_heavy_work do
  # Isso pode bloquear o scheduler!
  # O processo ficará executando por muito tempo sem preempção
  Enum.map(1..10_000_000, fn x -> :math.sqrt(x) end)
end

# ✅ Use Task.async para trabalho pesado
def good_heavy_work do
  task = Task.async(fn ->
    # Este cálculo roda em outro processo
    Enum.map(1..10_000_000, fn x -> :math.sqrt(x) end)
  end)
  Task.await(task)
end

# ❌ Evite mensagens gigantescas
def send_huge_message(pid) do
  huge_data = Enum.to_list(1..10_000_000)
  # A mensagem inteira será copiada para o destino!
  send(pid, huge_data)
end

# ✅ Use ETS ou binários compartilhados
def share_via_ets(pid) do
  huge_data = Enum.to_list(1..10_000_000)
  # Armazena uma vez, todos acessam por referência
  :ets.insert(:shared_table, {:data, huge_data})
  send(pid, {:ets_ref, :data})
end
```

***

### 12. RESUMO TÉCNICO

| Recurso                      | Descrição                                 | Impacto no Sistema                    |
| ---------------------------- | ----------------------------------------- | ------------------------------------- |
| **Garbage Collection**       | Coleta de lixo por processo, independente | Sem pausas globais ("stop-the-world") |
| **Hot Code Swapping**        | Atualização de código sem parar a VM      | Uptime de 9 noves (99.9999999%)       |
| **Imutabilidade**            | Dados são imutáveis por padrão            | Elimina condições de corrida e locks  |
| **Processos Leves**          | Processos BEAM com \~2-3KB                | Milhões de processos simultâneos      |
| **Escalonamento Preemptivo** | Processos interrompidos após reductions   | Latência previsível e baixa           |
| **Distribuição Nativa**      | Comunicação transparente entre nós        | Escalabilidade horizontal nativa      |

***

### 13. REFERÊNCIA RÁPIDA

#### 13.1 Comandos Essenciais

| Comando                            | Descrição                          | Uso Típico                |
| ---------------------------------- | ---------------------------------- | ------------------------- |
| `:erlang.system_info(:schedulers)` | Número total de schedulers         | Diagnóstico de capacidade |
| `:erlang.statistics(:run_queue)`   | Processos aguardando execução      | Detectar sobrecarga       |
| `:erlang.memory(:total)`           | Memória total da BEAM              | Monitoramento             |
| `Process.info(pid)`                | Informações detalhadas do processo | Debugging                 |
| `:observer.start()`                | Interface gráfica de monitoramento | Análise em tempo real     |
| `System.schedulers_online()`       | Schedulers ativos                  | Otimização                |

#### 13.2 Configurações da VM

```bash
# Opções de linha de comando da BEAM
elixir --erl "+S 4:4"      # 4 schedulers, 4 online
elixir --erl "+P 1000000"  # Máximo de processos (padrão: 262144)
elixir --erl "+hms 8192"   # Heap inicial em words (padrão: 233)
elixir --erl "+MBas ageffcbf"  # Ajustes do GC

# Environment variables
export ERL_MAX_PORTS=100000   # Máximo de portas/soquetes
export ERL_CRASH_DUMP=/tmp/erlang_crash.dump  # Local do dump
export ERL_FLAGS="+S 4:4 +P 500000"  # Flags padrão
```

#### 13.3 Conceitos Chave

```yaml
TERMOS BEAM ESSENCIAIS:
  Reduction: Unidade de trabalho da BEAM (~2000/time slice)
  Scheduler: Thread do SO que executa processos BEAM
  Run Queue: Fila de processos prontos para executar
  Preemption: Interrupção automática após reductions
  Message Copying: Mensagens copiadas entre processos
  Per-Process GC: Coleta de lixo independente
  ERTS: Erlang Runtime System (VM + kernel)

OTIMIZAÇÕES IMPORTANTES:
  Tail Call Optimization: Stack constante em recursão
  Binary Reference Counting: Compartilhamento eficiente
  ETS Shared Memory: Tabelas de acesso rápido
  Ports: Comunicação nativa com mundo externo
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/conceitos/programacao-e-linguagens/elixir/7.-beam-bogdan-erlang-abstract-machine.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
