跳到正文
原文
Google AI:DEV 作者专属(RSS)· Matheus de Camargo Marques·· 7 小时前AI 评分24

Elixir Enchiridium 第二卷《机器》:揭秘 BEAM 虚拟机内部架构

Elixir Enchiridium — Tomo II: A Máquina

AI 导读

Elixir Enchiridium 第二卷《机器》以讽刺奇幻形式讲解 BEAM 虚拟机架构,共一百章。BEAM 本身只是执行指令的虚拟机,并不理解进程、端口或 ETS 表,这些由 ERTS 管理;它是基于寄存器的机器,X 寄存器传递临时数据与函数参数,Y 寄存器为栈帧局部变量。

正文

AVISO: esta série é uma fantasia satírica baseada em fatos reais sobre Elixir. Nada aqui deve ser levado ao pé da letra. Ao final de cada capítulo, os fatos por trás da lenda são revelados. Tags: #satire #humor #elixir #enchiridium


Elixir Enchiridium — Tomo II: A Máquina

Prefácio do Tomo

No Tomo I, contamos a história de como Elixir nasceu. Um brasileiro ouviu um sussurro, uma linguagem foi criada, uma comunidade cresceu, empresas apostaram tudo. Foi a história da origem.

Agora vamos abrir a máquina.

Este tomo é sobre a BEAM — a máquina virtual que faz tudo funcionar. Não a BEAM como mito, mas a BEAM como engenharia. Vamos olhar para dentro: os processos leves, o scheduler, o garbage collector, o JIT, o hot code swapping, a distribuição, os alocadores de memória. Cada capítulo parte de um fato verificável sobre a arquitetura da BEAM e o transforma em uma crônica fantástica. Porque a verdade sobre a BEAM já é fantástica o suficiente.

São cem capítulos. O segundo tomo de dez.

Comecemos pelo começo: o que é a BEAM, afinal?


Capítulo 1 — BEAM: A Máquina que Não Sabe o Que É um Processo

A lenda diz que a BEAM é onisciente. Que ela sabe tudo sobre todos os processos, todas as mensagens, todas as tabelas ETS. Que ela é a máquina suprema, o cérebro da colmeia.

A verdade é mais estranha: a BEAM não sabe o que é um processo. Ela é apenas a máquina virtual. Ela executa instruções. Ela não tem noção de processos, portas, tabelas ETS, nada disso. Quem sabe sobre processos é o ERTS (Erlang Runtime System), que usa a BEAM como seu motor de execução.

A lenda diz que, na primeira vez que alguém perguntou à BEAM "O que é um processo?", ela respondeu: "Não sei. Pergunte ao ERTS." E continuou executando instruções.

O fato por trás da lenda: A BEAM é apenas a máquina virtual que executa instruções no Erlang Runtime System (ERTS). Ela não tem noção de processos, portas ou tabelas ETS. A BEAM é uma máquina de registradores, onde todas as instruções operam em registradores nomeados (X e Y). Cada registrador pode conter qualquer termo Erlang.

Gancho: Mas se a BEAM não sabe o que é um processo, como ela executa milhões deles?


Capítulo 2 — A Máquina de Registradores: X e Y, os Dois Guardiões

A lenda diz que a BEAM tem dois guardiões: X e Y. X é o guardião dos dados temporários, que passam entre funções sem precisar de stack frame. Y é o guardião dos dados locais, que ficam presos em seus stack frames até que alguém os chame.

A verdade é que a BEAM é uma máquina de registradores. As instruções operam em registradores nomeados. Os registradores X são usados para dados temporários e passagem de argumentos entre funções. Os registradores Y são locais a cada stack frame.

A lenda diz que, quando um programador perguntou "Por que X e Y?", o instrutor respondeu: "Porque Z era reservado para o eixo das perguntas sem resposta."

O fato por trás da lenda: A BEAM é uma máquina de registradores. Os registradores X são usados para dados temporários e passagem de argumentos entre funções. Os registradores Y são locais a cada stack frame. O controle de fluxo é feito por instruções que testam uma condição e saltam para um label.

Gancho: Com registradores X e Y, a BEAM executa instruções. Mas quem decide quais instruções executar? O scheduler.


Capítulo 3 — O Scheduler Preemptivo: O Juiz que Nunca Dorme

A lenda diz que o scheduler da BEAM é um juiz que nunca dorme. Ele olha para cada processo e diz: "Você já rodou o suficiente. Próximo." Os processos obedecem. Se não obedecessem, o scheduler os interromperia.

A verdade é que o scheduler da BEAM usa preempção baseada em reduções. Cada processo recebe uma cota de reduções (cerca de 4000). Uma redução é aproximadamente equivalente a uma chamada de função ou uma quantidade similar de trabalho. Quando o contador de reduções chega a zero, o processo é preemptado e colocado no fim da fila de prontos.

A lenda diz que o scheduler é justo porque nunca deixou um processo monopolizar a CPU. Nem mesmo o processo que queria calcular o último dígito de Pi.

O fato por trás da lenda: O scheduler da BEAM usa preempção baseada em reduções. Cada processo recebe uma cota de reduções (cerca de 4000). Uma redução é aproximadamente equivalente a uma chamada de função ou uma quantidade similar de trabalho. Quando o contador chega a zero, o processo é preemptado e colocado no fim da fila de prontos.

Gancho: O scheduler distribui reduções. Mas o que é uma redução, exatamente?


Capítulo 4 — Reduções: A Moeda do Tempo na BEAM

A lenda diz que, na BEAM, o tempo não é medido em segundos. É medido em reduções. Uma redução é a menor unidade de trabalho. Uma chamada de função custa uma redução. Uma operação aritmética custa uma redução. Uma mensagem custa uma redução. Se você tem reduções, você tem tempo. Se não tem, você espera.

A verdade é que o conceito de redução vem do Prolog. Em Prolog, cada passo de execução é chamado de "goal-reduction". A BEAM herdou o conceito e o usa para preempção. Cada processo recebe um orçamento de reduções e, quando ele acaba, o processo é suspenso.

A lenda diz que um programador tentou comprar reduções com café. Não funcionou. Mas ele conseguiu um aumento.

O fato por trás da lenda: O conceito de "redução" vem do Prolog, onde cada passo de execução é chamado de "goal-reduction". A BEAM usa reduções para preempção: cada processo recebe um orçamento de reduções e, quando ele acaba, o processo é suspenso e outro processo é executado.

Gancho: Reduções são a moeda. Mas há uma coisa que custa mais reduções que qualquer outra: a passagem de mensagens.


Capítulo 5 — Processos Leves: 327 Palavras de Pura Magia

A lenda diz que, na BEAM, cada processo é leve. Muito leve. Tão leve que você pode criar milhões deles sem suar. Tão leve que eles flutuam. Tão leve que, se você piscar, eles desaparecem.

A verdade é que um processo Erlang recém-criado usa 327 palavras de memória. Isso inclui 233 palavras para a área de heap (que inclui a stack). O garbage collector aumenta o heap conforme necessário. O heap inicial padrão de 233 palavras é conservador o suficiente para suportar sistemas com centenas de milhares ou até milhões de processos.

A lenda diz que, na primeira vez que um programador viu 327 palavras, ele perguntou: "Isso é tudo?" O instrutor respondeu: "É tudo." O programador chorou. De alegria.

O fato por trás da lenda: Um processo Erlang recém-criado usa 327 palavras de memória, incluindo 233 palavras para a área de heap (que inclui a stack). O garbage collector aumenta o heap conforme necessário. O heap inicial padrão de 233 palavras é conservador para suportar sistemas com milhões de processos.

Gancho: Processos leves são a base. Mas eles precisam de um lugar para guardar suas coisas. Esse lugar é o heap.


Capítulo 6 — Heap e Stack: Os Dois Irmãos que Crescem um para o Outro

A lenda diz que, na BEAM, heap e stack são dois irmãos que moram na mesma casa. Eles crescem um em direção ao outro. Quando se encontram, o garbage collector aparece e os separa. Se não conseguir, o heap cresce.

A verdade é que cada processo Erlang tem seu próprio stack e heap, alocados no mesmo bloco de memória. Eles crescem um em direção ao outro. Quando a stack e o heap se encontram, o garbage collector é acionado e a memória é recuperada. Se não foi recuperada o suficiente, o heap cresce.

A lenda diz que, quando o garbage collector aparece, ele diz: "Vocês dois, se afastem." E eles se afastam.

O fato por trás da lenda: Cada processo Erlang tem seu próprio stack e heap, alocados no mesmo bloco de memória. Eles crescem um em direção ao outro. Quando se encontram, o garbage collector é acionado e a memória é recuperada. Se não foi recuperada o suficiente, o heap cresce.

Gancho: Heap e stack crescem. Mas eles não crescem sozinhos. Há um garbage collector que cuida disso.


Capítulo 7 — O Garbage Collector por Processo: A Pausa que Não Existe

A lenda diz que, na maioria das linguagens, o garbage collector para o mundo. Na BEAM, não. Cada processo tem seu próprio garbage collector. Cada processo coleta seu próprio lixo. O resultado é que a BEAM não tem pausas longas de GC.

A verdade é que o garbage collector da BEAM é um coletor geracional semi-space copying por processo, usando o algoritmo de Cheney, com um espaço global para grandes objetos. Cada processo tem seu próprio heap e seu próprio GC. Quando um processo precisa coletar lixo, ele coleta apenas o seu próprio heap, sem afetar os outros processos.

A lenda diz que, na primeira vez que um programador viu isso, ele perguntou: "Onde está a pausa?" O instrutor respondeu: "Não tem." O programador perguntou: "Como assim?" O instrutor respondeu: "Cada processo coleta seu próprio lixo." O programador ficou em silêncio por dez minutos.

O fato por trás da lenda: O garbage collector da BEAM é um coletor geracional semi-space copying por processo, usando o algoritmo de Cheney, com um espaço global para grandes objetos. Cada processo tem seu próprio heap e seu próprio GC. A coleta de lixo não pausa o sistema inteiro.

Gancho: O GC coleta lixo. Mas há uma coisa que ele não pode coletar: mensagens na mailbox.


Capítulo 8 — A Mailbox: O Correio que Nunca Fecha

A lenda diz que cada processo na BEAM tem uma mailbox. É um lugar onde as mensagens chegam e esperam. A mailbox nunca fecha. Nunca transborda. Nunca perde uma mensagem. Se o processo está ocupado, a mensagem espera. Se o processo está dormindo, a mensagem espera. Se o processo morreu, a mensagem... bem, aí é problema de quem enviou.

A verdade é que cada processo tem uma mailbox onde as mensagens são enfileiradas. As mensagens são enviadas de forma assíncrona. O processo receptor pode usar receive para buscar seletivamente mensagens da mailbox, usando pattern matching. Se nenhuma mensagem casar, o processo bloqueia até que uma mensagem que case chegue.

A lenda diz que, na primeira vez que um programador viu uma mailbox, ele perguntou: "E se ela encher?" O instrutor respondeu: "Ela não enche. Ela só cresce." O programador perguntou: "E se crescer demais?" O instrutor respondeu: "Aí você tem um problema."

O fato por trás da lenda: Cada processo na BEAM tem uma mailbox onde as mensagens são enfileiradas. As mensagens são enviadas de forma assíncrona. O processo receptor pode usar receive para buscar seletivamente mensagens da mailbox, usando pattern matching.

Gancho: A mailbox recebe mensagens. Mas como elas chegam até lá?


Capítulo 9 — Passagem de Mensagens: A Cópia que Salva Vidas

A lenda diz que, na BEAM, quando um processo envia uma mensagem para outro, a mensagem é copiada. Não é compartilhada. Não é passada por referência. É copiada. Isso significa que o processo que envia não pode modificar a mensagem depois de enviada. Isso significa que o processo que recebe não pode modificar a mensagem do processo que enviou. Isso significa que não há condições de corrida.

A verdade é que todos os dados em mensagens enviadas entre processos Erlang são copiados, exceto por refc binaries (binários grandes) e alguns outros casos especiais. Isso elimina a necessidade de locks e evita condições de corrida.

A lenda diz que, na primeira vez que um programador viu isso, ele perguntou: "Copiar não é lento?" O instrutor respondeu: "É mais lento que compartilhar. Mas é mais rápido que debugar uma condição de corrida."

O fato por trás da lenda: Todos os dados em mensagens enviadas entre processos Erlang são copiados, exceto por refc binaries e alguns outros casos especiais. Isso elimina a necessidade de locks e evita condições de corrida.

Gancho: Mensagens são copiadas. Mas nem tudo na BEAM é copiado. Há um lugar onde os dados são compartilhados: o ETS.


Capítulo 10 — ETS: A Tabela que Todos Compartilham (e Ninguém Odeia)

A lenda diz que, na BEAM, existe um lugar onde os dados são compartilhados. Chama-se ETS (Erlang Term Storage). É uma tabela onde qualquer processo pode ler e escrever. Não há cópia. Não há isolamento. Há apenas dados, compartilhados, acessíveis. E, milagrosamente, ninguém briga por eles.

A verdade é que ETS é uma tabela em memória que armazena termos Erlang. Ela é compartilhada entre processos e é uma das poucas formas de compartilhar dados na BEAM sem cópia. ETS é frequentemente usada para cache, para contadores e para armazenar dados que precisam ser acessados rapidamente por múltiplos processos.

A lenda diz que, quando um programador perguntou "Como vocês evitam condições de corrida no ETS?", o instrutor respondeu: "Com locks." O programador perguntou: "Mas vocês não odeiam locks?" O instrutor respondeu: "Odeio. Por isso uso ETS com moderação."

O fato por trás da lenda: ETS (Erlang Term Storage) é uma tabela em memória que armazena termos Erlang. Ela é compartilhada entre processos e é uma das poucas formas de compartilhar dados na BEAM sem cópia. ETS é usada para cache, contadores e dados de acesso rápido.

Gancho: ETS compartilha dados. Mas há uma coisa que compartilha mais: a distribuição.


Capítulo 11 — Distribuição: A BEAM que Atravessa Oceanos

A lenda diz que a BEAM não roda em uma máquina. Ela roda em várias. Ela se conecta a outras BEAMs, forma clusters, compartilha processos. Uma mensagem enviada para um processo em Tóquio chega em milissegundos. Um processo que morre em Londres é detectado em Nova York. A BEAM é onipresente.

A verdade é que a BEAM tem distribuição embutida. Nós Erlang podem se conectar e formar clusters. Processos podem ser distribuídos entre nós. Mensagens podem ser enviadas para processos em outros nós. A distribuição é transparente para o programador: send(pid, msg) funciona igual, seja o processo local ou remoto.

A lenda diz que, na primeira vez que um programador viu um cluster BEAM, ele perguntou: "Como vocês fizeram isso?" O instrutor respondeu: "Não fizemos. Já vem de fábrica."

O fato por trás da lenda: A BEAM tem distribuição embutida. Nós Erlang podem se conectar e formar clusters. Processos podem ser distribuídos entre nós. Mensagens podem ser enviadas para processos em outros nós. A distribuição é transparente para o programador.

Gancho: Distribuição é poderosa. Mas ela traz um problema: como os nós se encontram?


Capítulo 12 — Libcluster: O Feitiço que Junta os Nós

A lenda diz que, para formar um cluster Elixir, você precisa de magia. Você roda libcluster e, de repente, todos os nós se encontram, se cumprimentam e começam a trabalhar juntos. Se um nó morre, os outros sentem falta. Se um nó nasce, os outros dão boas-vindas.

A verdade é que o Libcluster fornece um mecanismo para formar automaticamente clusters de nós Erlang, com adesão estática ou dinâmica. Ele suporta várias estratégias: EPMD, Kubernetes, Gossip, DNS, e outras.

A lenda diz que, na primeira vez que um programador usou Libcluster, ele perguntou: "Como isso funciona?" O instrutor respondeu: "Magia." O programador perguntou: "Mas como?" O instrutor respondeu: "Magia com estratégia."

O fato por trás da lenda: Libcluster fornece formação automática de clusters de nós Erlang, com adesão estática ou dinâmica. Ele suporta várias estratégias: EPMD, Kubernetes, Gossip, DNS, e outras.

Gancho: Libcluster conecta nós. Mas há uma coisa que mantém eles conectados: a tolerância a falhas.


Capítulo 13 — Tolerância a Falhas: A Filosofia que Virou Benchmark

A lenda diz que, num benchmark acadêmico, o Elixir foi comparado a outras linguagens concorrentes sob condições de falha. O resultado? "Elixir atingiu o maior throughput e a menor variabilidade de throughput sob condições de falha". Os aliens aplaudiram. Os humanos tomaram café.

A verdade é que a tolerância a falhas da BEAM é um dos seus pontos mais fortes. Processos isolados, supervisores, árvores de supervisão, "let it crash" — tudo isso faz com que sistemas BEAM se recuperem de falhas de forma quase automática.

O fato por trás da lenda: A tolerância a falhas da BEAM é um dos seus pontos mais fortes. Processos isolados, supervisores, árvores de supervisão, "let it crash" — tudo isso faz com que sistemas BEAM se recuperem de falhas de forma quase automática.

Gancho: Tolerância a falhas é a base. Mas há uma coisa que mantém os processos vivos: os supervisores.


Capítulo 14 — Supervisores: As Babás que Nunca Dormem

A lenda diz que os supervisores são babás que dão mamadeira para processos órfãos. Se um processo morre, a babá chora, pega um novo processo no berçário e coloca no lugar. A estratégia one_for_one significa que ela só troca uma fralda por vez. A rest_for_one é quando ela troca todas as fraldas da fileira. A one_for_all é quando ela surta e reinicia o berçário inteiro.

A verdade é que supervisores são processos que monitoram outros processos (chamados de processos filhos) e os reiniciam quando falham. Supervisores formam árvores de supervisão que fornecem tolerância a falhas e capacidades de auto-recuperação.

O fato por trás da lenda: Supervisores monitoram processos filhos e os reiniciam quando falham. Supervisores formam árvores de supervisão que fornecem tolerância a falhas e auto-recuperação.

Gancho: Supervisores cuidam. Mas há um processo que serve: o GenServer.


Capítulo 15 — GenServer: O Mordomo que Serve Estado em Bandejas

A lenda diz que um GenServer é um mordomo chamado Alfred que guarda o estado do seu sistema em uma bandeja de prata. Quando você chama GenServer.call, ele responde "Pois não, senhor" e executa a função. Se você usar GenServer.cast, ele anota o recado e vai fazer depois, sem pressa.

A verdade é que GenServer é um comportamento do OTP para construir servidores genéricos. Ele encapsula estado e concorrência, permitindo que você defina callbacks para lidar com chamadas síncronas e assíncronas. GenServer é um dos blocos de construção fundamentais de aplicações Elixir.

O fato por trás da lenda: GenServer é um comportamento do OTP para construir servidores genéricos. Ele encapsula estado e concorrência, com callbacks para chamadas síncronas e assíncronas.

Gancho: GenServer serve. Mas há uma coisa que persiste: o Ecto.


Capítulo 16 — Ecto: O Fantasma que Assombra Bancos de Dados

A lenda diz que Ecto é um fantasma que mora no seu PostgreSQL e escreve queries em latim. Cada Repo.insert é um exorcismo. Se você esquecer de fechar a transação, o fantasma sai do banco e assombra seu servidor.

A verdade é que Ecto é uma biblioteca de persistência para Elixir. Ele fornece uma camada de mapeamento entre o código Elixir e o banco de dados, com suporte a migrações, queries e transações. Ecto é dividido em quatro componentes principais: Ecto.Repo, Ecto.Schema, Ecto.Query e Ecto.Changeset.

O fato por trás da lenda: Ecto é uma biblioteca de persistência para Elixir, com componentes para repositórios, schemas, queries e changesets. Ele fornece mapeamento de dados e queries integradas à linguagem.

Gancho: Ecto persiste. Mas há uma coisa que conecta tudo: o Phoenix.


Capítulo 17 — Phoenix: A Fênix que Nasceu das Cinzas

A lenda diz que Phoenix é um framework web que invoca uma fênix de verdade. Cada vez que você roda mix phx.server, uma fênix renasce das cinzas no Arizona. Isso consome 3% da energia mundial, mas o hot reload é instantâneo.

A verdade é que Phoenix é um framework web para Elixir, criado por Chris McCord. Ele foi lançado em 2015 e se tornou o framework web padrão para Elixir. Phoenix aproveita a BEAM para fornecer alta performance e concorrência, e o LiveView permite criar aplicações interativas sem JavaScript.

O fato por trás da lenda: Phoenix é um framework web para Elixir, criado por Chris McCord e lançado em 2015. Ele se tornou o framework web padrão para Elixir e inclui o LiveView para aplicações interativas sem JavaScript.

Gancho: Phoenix constrói. Mas há uma coisa que conecta usuários: o LiveView.


Capítulo 18 — LiveView: A Janela para o Multiverso

A lenda diz que, na primeira vez que alguém rodou uma LiveView, uma janela para outra dimensão se abriu no navegador. O usuário viu o conteúdo em tempo real porque estava literalmente olhando para o multiverso.

A verdade é que Phoenix LiveView permite construir experiências de usuário ricas e em tempo real com HTML renderizado no servidor, sem escrever JavaScript. O servidor gerencia o estado e envia atualizações de UI pela conexão WebSocket. A versão 1.0 foi lançada em dezembro de 2024.

O fato por trás da lenda: Phoenix LiveView permite construir aplicações interativas renderizadas no servidor sem JavaScript. A versão 1.0 foi lançada em dezembro de 2024.

Gancho: LiveView interage. Mas há uma coisa que conecta nós: o Libcluster.


Capítulo 19 — OTP 26 e o JIT: A BEAM Ficou Mais Rápida

A lenda diz que, em 2023, a Ericsson lançou o OTP 26. A grande novidade era o compilador JIT estendido. A BEAM sempre foi interpretada, mas com o JIT, ela passou a compilar código para linguagem de máquina em tempo de execução. O resultado foi um ganho de performance significativo. O JIT do OTP 26 estendeu as otimizações baseadas em tipos, resultando em menos testes de tipo redundantes e código nativo menor.

A verdade é que o OTP 26 introduziu otimizações estendidas baseadas em tipos no compilador e JIT. O compilador passou a produzir melhores informações de tipo, e o JIT passou a aproveitá-las, resultando em menos testes de tipo redundantes e código nativo menor.

O fato por trás da lenda: OTP 26 introduziu otimizações estendidas baseadas em tipos no compilador e JIT. O compilador passou a produzir melhores informações de tipo, e o JIT passou a aproveitá-las, resultando em menos testes de tipo redundantes e código nativo menor.

Gancho: O JIT tornou a BEAM mais rápida. Mas há uma coisa que sempre foi rápida: os processos leves.


Capítulo 20 — Hot Code Swapping: A Magia de Trocar o Motor com o Carro Andando

A lenda diz que, na BEAM, você pode trocar o motor com o carro andando. Você atualiza o código de um sistema em execução sem pará-lo. Sem downtime. Sem reiniciar. O sistema continua rodando enquanto o código é trocado.

A verdade é que o hot code swapping é uma das características mais distintivas da BEAM. Ela permite que o código de um sistema em execução seja atualizado sem pará-lo. Isso é possível porque a BEAM mantém duas versões do código em memória: a antiga e a nova. Quando um processo precisa executar uma função, ele usa a versão mais recente. O OTP fornece o callback code_change/3 para migrar o estado entre versões.

A lenda diz que, na primeira vez que um engenheiro da Ericsson viu o hot code swapping em ação, ele disse: "Isso é impossível." O sistema respondeu: "Não é." E continuou rodando.

O fato por trás da lenda: Hot code swapping é uma das características mais distintivas da BEAM. Ela permite que o código de um sistema em execução seja atualizado sem pará-lo. A BEAM mantém duas versões do código em memória, e o OTP fornece o callback code_change/3 para migrar o estado.

Gancho: Hot code swapping é uma revolução. Mas há uma coisa que nem a BEAM consegue fazer: prever o futuro.


Capítulo 21 — Ports e NIFs: As Janelas para o Mundo

A lenda diz que a BEAM não roda sozinha. Ela precisa se comunicar com o mundo exterior. Para isso, ela usa Ports e NIFs. Ports permitem que a BEAM se comunique com programas externos. NIFs permitem que a BEAM execute código nativo.

A verdade é que Ports movem código perigoso para um processo de SO separado, garantindo segurança e isolamento. NIFs (Native Implemented Functions) executam código nativo diretamente na thread do scheduler da BEAM, oferecendo performance máxima mas com risco de travar a máquina virtual inteira. Com Erlang/OTP 20+, existem Dirty NIFs, que executam em um pool de threads dedicado, permitindo cálculos longos sem bloquear o scheduler.

A lenda diz que, quando um programador descobriu os NIFs, ele disse: "Posso escrever código C e rodar na BEAM?" O instrutor respondeu: "Pode. Mas cuidado." O programador perguntou: "Por quê?" O instrutor respondeu: "Porque se o NIF travar, a BEAM inteira trava." O programador ficou em silêncio.

O fato por trás da lenda: Ports movem código para um processo de SO separado. NIFs executam código nativo na thread do scheduler, com performance máxima mas risco de travar a BEAM. Dirty NIFs executam em pool de threads dedicado.

Gancho: Ports e NIFs são as janelas da BEAM. Mas há uma ferramenta que observa tudo: o Observer.


Capítulo 22 — Observer: A Janela para a Alma da BEAM

A lenda diz que, se você quer ver a alma da BEAM, abra o Observer. Ele mostra todos os processos, todos os nós, toda a memória. Você vê a máquina respirando. Você vê os processos nascendo e morrendo. Você vê a BEAM viva.

A verdade é que o Observer é uma ferramenta gráfica para inspecionar sistemas Erlang/Elixir em execução. Ele mostra informações do sistema, árvores de supervisão de aplicações, informações de processos, tabelas ETS ou Mnesia, e contém um frontend para tracing de Erlang. Ele também inclui o etop (uma ferramenta para apresentar informações sobre processos Erlang) e o crashdump_viewer (uma ferramenta HTML para navegar em crashdumps).

A lenda diz que, na primeira vez que um programador abriu o Observer, ele perguntou: "O que é isso?" O instrutor respondeu: "A alma da BEAM." O programador ficou olhando por uma hora.

O fato por trás da lenda: Observer é uma ferramenta gráfica para inspecionar sistemas Erlang/Elixir em execução. Ele mostra informações do sistema, árvores de supervisão, informações de processos, tabelas ETS e contém frontend para tracing. Inclui etop e crashdump_viewer.

Gancho: Observer mostra a alma. Mas há uma coisa que nem o Observer consegue mostrar: o futuro.


Capítulo 23 — O Futuro da BEAM: Tipos, IA e a Máquina do Amanhã

A lenda diz que o futuro da BEAM é tipado, inteligente e distribuído. O v1.20 trouxe inferência de tipos. O Nx trouxe IA. O LiveView trouxe interatividade sem JavaScript. E a BEAM continua rodando, com suas capivaras quânticas girando manivelas.

A verdade é que a BEAM está evoluindo. O Elixir está se tornando gradualmente tipado, com inferência de tipos de todos os construtos no v1.20. O Nx está trazendo ML para a BEAM. O LiveView está redefinindo o desenvolvimento web. E a comunidade continua crescendo.

O fato por trás da lenda: A BEAM está evoluindo. O Elixir está se tornando gradualmente tipado. O Nx traz ML para a BEAM. O LiveView redefine o desenvolvimento web. A comunidade cresce.

Gancho: O futuro é promissor. Mas antes de terminar este tomo, precisamos falar de uma coisa: o alocador de memória.


Capítulo 24 — erts_alloc: O Alocador que Ninguém Vê

A lenda diz que, na BEAM, há um alocador de memória chamado erts_alloc. Ele é invisível. Ele trabalha nos bastidores. Ele aloca memória para processos, para ETS, para binários. Ele nunca reclama. Ele nunca para. Ele é o herói anônimo da BEAM.

A verdade é que erts_alloc é a biblioteca de alocação de memória interna do Erlang Runtime System. Ele fornece vários alocadores especializados para diferentes tipos de dados: ets_alloc para tabelas ETS, binary_alloc para binários, eheap_alloc para heaps de processos, e muitos outros. A ideia principal é ter alocadores separados para diferentes tipos de dados, melhorando a performance e reduzindo a fragmentação.

A lenda diz que, quando um programador perguntou "Onde está o alocador?", o instrutor respondeu: "Em todo lugar." O programador perguntou: "Posso vê-lo?" O instrutor respondeu: "Só se você olhar para o código-fonte."

O fato por trás da lenda: erts_alloc é a biblioteca de alocação de memória interna do Erlang Runtime System. Ele fornece alocadores especializados para diferentes tipos de dados: ets_alloc, binary_alloc, eheap_alloc, e outros. A ideia é ter alocadores separados para melhorar performance e reduzir fragmentação.

Gancho: O alocador trabalha. Mas há uma coisa que ele não pode alocar: tempo.


Capítulo 25 — BEAM vs. JVM: A Batalha dos Titãs

A lenda diz que, há muito tempo, em um mundo distante, duas máquinas virtuais lutaram pelo domínio. De um lado, a JVM, com sua hierarquia de classes e seu garbage collector "stop-the-world". Do outro, a BEAM, com seus processos leves e seu GC por processo. A batalha durou décadas. A JVM ganhou em popularidade. A BEAM ganhou em concorrência.

A verdade é que a JVM e a BEAM têm filosofias diferentes. A JVM foi projetada para rodar código Java, com foco em portabilidade e ecossistema. A BEAM foi projetada para telecomunicações, com foco em concorrência e tolerância a falhas. A JVM tem um heap compartilhado e um GC global. A BEAM tem heaps por processo e GC por processo.

A lenda diz que, quando perguntaram a Joe Armstrong qual era a melhor, ele respondeu: "A que não para o mundo."

O fato por trás da lenda: A JVM e a BEAM têm filosofias diferentes. A JVM tem um heap compartilhado e um GC global. A BEAM tem heaps por processo e GC por processo. A JVM foi projetada para portabilidade e ecossistema. A BEAM foi projetada para concorrência e tolerância a falhas.

Gancho: JVM e BEAM são diferentes. Mas há uma coisa que ambas têm em comum: ambas rodam código.


Capítulo 26 — O Código que a BEAM Executa: BEAM Assembly

A lenda diz que a BEAM não executa código Erlang. Ela executa BEAM assembly. Quando você compila um módulo Erlang ou Elixir, ele é traduzido para instruções BEAM. Essas instruções operam em registradores. Elas testam condições. Elas saltam. Elas chamam funções. A BEAM executa essas instruções como um intérprete de código threaded.

A verdade é que a BEAM é uma máquina de registradores. Quando você compila código Erlang, ele é traduzido para instruções BEAM como {move, {integer,0}, {x,1}} e {call_only,2,{f,4}}. A BEAM executa essas instruções como um intérprete de código threaded, ou, com o JIT, como código nativo.

A lenda diz que, quando um programador viu o BEAM assembly pela primeira vez, ele perguntou: "Isso é Assembly?" O instrutor respondeu: "É BEAM assembly." O programador perguntou: "Qual a diferença?" O instrutor respondeu: "BEAM assembly é bonito."

O fato por trás da lenda: A BEAM executa instruções BEAM, que são geradas pela compilação de código Erlang ou Elixir. As instruções operam em registradores e são executadas como um intérprete de código threaded ou, com o JIT, como código nativo.

Gancho: A BEAM executa instruções. Mas quem decide quais instruções? O carregador de código.


Capítulo 27 — O Carregador de Código: O Bibliotecário da BEAM

A lenda diz que, na BEAM, há um bibliotecário chamado code server. Ele guarda todos os módulos. Quando você chama uma função, ele busca o módulo. Quando você carrega um novo módulo, ele o adiciona à estante. Quando você remove um módulo, ele o tira da estante. Ele nunca perde um livro. Ele nunca atrasa uma entrega.

A verdade é que o code server é o processo responsável por gerenciar o código carregado na BEAM. Ele mantém duas versões de cada módulo: a old e a current. Quando um novo módulo é carregado, a versão atual se torna a antiga, e a nova se torna a atual. O code server também é responsável por fazer o purge das versões antigas quando não são mais necessárias.

A lenda diz que, quando um programador perguntou "Onde está o módulo?", o bibliotecário respondeu: "Qual versão?" O programador perguntou: "Existe mais de uma?" O bibliotecário sorriu.

O fato por trás da lenda: O code server é o processo responsável por gerenciar o código carregado na BEAM. Ele mantém duas versões de cada módulo: a old e a current. Quando um novo módulo é carregado, a versão atual se torna a antiga, e a nova se torna a atual.

Gancho: O bibliotecário guarda os módulos. Mas há uma coisa que ele não guarda: o estado dos processos.


Capítulo 28 — O Estado dos Processos: O Que Ninguém Vê

A lenda diz que, na BEAM, cada processo tem um estado. Esse estado é invisível. Ninguém pode vê-lo. Ninguém pode tocá-lo. Só o próprio processo sabe o que guarda. E, quando o processo morre, o estado desaparece. Para sempre.

A verdade é que o estado de um processo Erlang é mantido em uma struct chamada Process. Na prática, a BEAM mantém parte do estado em variáveis locais e registradores da CPU, e precisa salvar essa parte na struct Process quando o processo é suspenso.

A lenda diz que, quando um programador perguntou "Onde está o estado?", o instrutor respondeu: "No processo." O programador perguntou: "Posso vê-lo?" O instrutor respondeu: "Só se você for o processo."

O fato por trás da lenda: O estado de um processo Erlang é mantido em uma struct chamada Process. A BEAM mantém parte do estado em variáveis locais e registradores da CPU, salvando essa parte na struct Process quando o processo é suspenso.

Gancho: O estado é invisível. Mas há uma coisa que torna o estado visível: o tracing.


Capítulo 29 — Tracing: O Olho que Tudo Vê (Se Você Pedir)

A lenda diz que, na BEAM, você pode ver tudo. Cada mensagem enviada. Cada função chamada. Cada processo criado. Basta ligar o tracing. O tracing é como uma câmera de segurança para o seu código. Ele registra tudo. Ele não mente. Ele não esquece.

A verdade é que a BEAM tem ferramentas de tracing poderosas, como dbg, ttb, e o frontend de tracing do Observer. Você pode rastrear chamadas de função, envio de mensagens, criação de processos, e muito mais. O tracing é uma das ferramentas mais poderosas para debugging e profiling de sistemas BEAM.

A lenda diz que, quando um programador ligou o tracing pela primeira vez, ele viu tudo. Ele viu cada mensagem. Ele viu cada função. Ele ficou tonto. Depois de dez minutos, ele desligou. "É muita informação", disse ele. O instrutor respondeu: "Por isso você filtra."

O fato por trás da lenda: A BEAM tem ferramentas de tracing como dbg, ttb, e o frontend do Observer. Você pode rastrear chamadas de função, envio de mensagens, criação de processos, e muito mais. O tracing é uma das ferramentas mais poderosas para debugging e profiling.

Gancho: O tracing vê tudo. Mas há uma coisa que nem o tracing vê: o futuro da BEAM.


Capítulo 30 — O Futuro da BEAM: O Que Vem Depois do JIT

A lenda diz que, depois do JIT, a BEAM ficará ainda mais rápida. O OTP 27 trouxe otimizações de record. O OTP 28 trará mais. E o OTP 29? Ninguém sabe. Mas a BEAM continuará rodando. Com suas capivaras quânticas girando manivelas, seus pombos treinados decidindo matches, e seus anões coletando lixo.

A verdade é que a BEAM continua evoluindo. O OTP 27 introduziu otimizações de record operations. O OTP 28 trará mais otimizações. O JIT continua sendo melhorado. E a comunidade continua contribuindo.

O fato por trás da lenda: A BEAM continua evoluindo. O OTP 27 introduziu otimizações de record operations. O OTP 28 trará mais otimizações. O JIT continua sendo melhorado.

Gancho: O futuro é promissor. Mas há uma coisa que sempre foi promissora: a comunidade.


Epílogo Parcial do Tomo II

Trinta capítulos. Uma máquina. Mil processos. E um brasileiro que ouviu um sussurro.

Este foi o começo do Tomo II — A Máquina. Ainda faltam 70 capítulos para completar este tomo. Nos próximos, vamos explorar: distribuição, clustering, alocadores de memória, Phoenix LiveView, OTP, ports e NIFs, ferramentas de observação, e muitos outros tópicos.

Até lá.


Agora, sério: A BEAM é a máquina virtual que executa Erlang, Elixir e outras linguagens. Ela foi projetada para telecomunicações e é usada por WhatsApp, Discord, Remote e muitas outras empresas. Os processos são leves (327 palavras), o scheduler é preemptivo, o GC é por processo, o JIT do OTP 26 melhorou a performance, e o hot code swapping é real. As capivaras quânticas não são reais — mas deveriam ser. Este artigo é uma fantasia satírica baseada em fatos. Mantenha o aviso para não enganar ninguém.

来源:Google AI:DEV 作者专属(RSS) · dev.to