惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
H
Help Net Security
Last Week in AI
Last Week in AI
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
IT之家
IT之家
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
Jina AI
Jina AI
Google DeepMind News
Google DeepMind News
B
Blog
C
Check Point Blog
T
Tailwind CSS Blog
云风的 BLOG
云风的 BLOG
D
Docker
Recent Announcements
Recent Announcements
Vercel News
Vercel News
博客园 - 聂微东
阮一峰的网络日志
阮一峰的网络日志
MyScale Blog
MyScale Blog
The GitHub Blog
The GitHub Blog
Stack Overflow Blog
Stack Overflow Blog
雷峰网
雷峰网
人人都是产品经理
人人都是产品经理
月光博客
月光博客
F
Fortinet All Blogs
Blog — PlanetScale
Blog — PlanetScale
B
Blog RSS Feed
The Register - Security
The Register - Security
V
Visual Studio Blog
F
Full Disclosure
Hugging Face - Blog
Hugging Face - Blog
T
Threat Research - Cisco Blogs
Latest news
Latest news
PCI Perspectives
PCI Perspectives
Cisco Talos Blog
Cisco Talos Blog
博客园 - Franky
D
DataBreaches.Net
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
Google Developers Blog
P
Palo Alto Networks Blog
Engineering at Meta
Engineering at Meta
Microsoft Azure Blog
Microsoft Azure Blog
T
Tenable Blog
L
LINUX DO - 热门话题
Spread Privacy
Spread Privacy

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
The BEAM Is Not Like Other Runtimes (And That's Why Elixir Scales the Way It Does)
shayan holak · 2026-04-28 · via DEV Community

You have been writing Elixir for a while. You know GenServers. You know supervisors. You have hit the BEAM's concurrency model enough times to trust it. But there is a level below that which most Elixir developers never look at, and it explains a lot of behavior that otherwise seems like magic.

Why does spawning a hundred thousand processes not kill your system? Why is a process crash isolated but not silent? Why does garbage collection in Elixir not stop the world? The answers are all in the BEAM, and they are worth understanding properly.

The BEAM Is Not the JVM With a Different Language

This comparison comes up constantly and it misleads people. Both are virtual machines that run bytecode. That is roughly where the similarity ends.

The JVM was designed around threads. Concurrency on the JVM means OS threads, shared mutable state, locks, and a garbage collector that operates across the entire heap. The BEAM was designed around processes. Not OS processes. Not OS threads. Its own lightweight processes, each with isolated memory, independent garbage collection, and message passing as the only communication mechanism.

This is not an implementation detail. It is the fundamental design decision that every other property of the BEAM follows from.

Processes Are Cheaper Than You Think

When people hear "process" they think OS process: expensive, slow to start, heavy on memory. BEAM processes are none of those things.

A BEAM process starts with around 2KB of stack space. It grows as needed. Spawning one takes microseconds. The BEAM scheduler manages thousands of them across a small pool of OS threads, one per CPU core by default. You can run a million concurrent processes on a single machine without the OS knowing about most of them.

# This is not dangerous. It is idiomatic.
pids = Enum.map(1..100_000, fn i ->
  spawn(fn ->
    Process.sleep(:timer.seconds(10))
    IO.puts("Process #{i} done")
  end)
end)

IO.puts("Spawned #{length(pids)} processes")
# => Spawned 100000 processes

Enter fullscreen mode Exit fullscreen mode

On most systems this runs without issue. Try the equivalent with OS threads in any language and you will run out of resources before you hit ten thousand. The difference is not hardware. It is the scheduler.

The Scheduler: Preemptive and Reduction-Based

The BEAM uses a preemptive scheduler, but not in the way most runtimes do it. It does not preempt based on time slices measured in milliseconds. It preempts based on reductions.

A reduction is roughly one unit of work: a function call, a pattern match, a message send. Each process gets a budget of 2000 reductions per scheduling turn. When the budget runs out, the scheduler suspends the process and runs another one. This happens regardless of what the process is doing. A tight loop does not starve other processes.

# This does not block the scheduler
defmodule Spinner do
  def spin(n) do
    spin(n + 1)  # each call consumes a reduction
  end
end

spawn(fn -> Spinner.spin(0) end)
spawn(fn -> IO.puts("I still run") end)
# => I still run

Enter fullscreen mode Exit fullscreen mode

In Node.js, a synchronous tight loop blocks the event loop entirely. In the BEAM, the scheduler preempts it after 2000 reductions. Every other process continues running. The misbehaving process gets its turn again shortly, but it cannot monopolize the system.

This is why latency in Elixir systems tends to be consistent rather than spiky. No single process can hold the scheduler hostage.

Memory Isolation and Per-Process GC

Every BEAM process has its own heap. No sharing. When a process dies, its heap is reclaimed immediately. No coordination with other processes, no waiting for a global GC cycle.

This is the source of one of the BEAM's most important properties: garbage collection does not stop the world. There is no world to stop. Each process collects its own garbage independently, on its own schedule, without affecting any other process.

# Each process allocates and collects independently
spawn(fn ->
  large_list = Enum.to_list(1..1_000_000)
  # large_list is only in this process's heap
  # GC here affects nothing else
  :ok
end)

# This process is unaffected by the GC above
spawn(fn ->
  IO.puts("Running without pause")
end)

Enter fullscreen mode Exit fullscreen mode

Compare this to the JVM's stop-the-world pauses, or Go's GC which, while incremental, still coordinates across the entire heap. In the BEAM, a process doing heavy allocation and collection does not introduce latency spikes in other processes. The isolation is complete.

The tradeoff is message passing. Because processes share no memory, sending data between them requires copying. Large messages are expensive not because of the send itself but because of the copy. This is why Elixir idioms tend toward small, frequent messages rather than large data transfers. The design pushes you toward the pattern that performs well.

How Message Passing Actually Works

Every process has a mailbox. Sending a message puts a copy of the message into the recipient's mailbox. The recipient reads from its mailbox using receive. This is asynchronous by default: sending does not block.

parent = self()

spawn(fn ->
  send(parent, {:result, 42})
end)

receive do
  {:result, value} -> IO.puts("Got: #{value}")
after
  5000 -> IO.puts("Timed out")
end

Enter fullscreen mode Exit fullscreen mode

The receive block pattern matches against messages in the mailbox in order. If no message matches, the process blocks and waits. Unmatched messages stay in the mailbox. This is a subtle point: if you receive messages without handling all patterns, your mailbox grows unboundedly. A common bug in long-running processes is accumulating unmatched messages until memory pressure becomes a problem.

# Dangerous in a long-running process
receive do
  {:ok, value} -> handle(value)
  # no catch-all: anything else stays in mailbox forever
end

# Safer
receive do
  {:ok, value} -> handle(value)
  other -> Logger.warning("Unexpected message: #{inspect(other)}")
end

Enter fullscreen mode Exit fullscreen mode

Preemption vs Cooperation: The NIF Problem

The BEAM's scheduler is preemptive for Elixir and Erlang code. It is not preemptive for NIFs.

A NIF (Native Implemented Function) is C code called directly from Elixir. When a NIF runs, the BEAM scheduler cannot preempt it. The OS thread running that NIF is blocked for the duration of the call. If your NIF takes 100ms, every process scheduled on that OS thread waits 100ms.

# If :my_nif.heavy_computation/1 takes 500ms,
# it blocks the scheduler thread for 500ms
result = :my_nif.heavy_computation(data)

Enter fullscreen mode Exit fullscreen mode

This is why the BEAM documentation is so emphatic that NIFs must be fast. Anything over one millisecond should use a dirty scheduler: a separate pool of OS threads reserved for long-running native calls that runs outside the main scheduler.

# In your NIF definition (C side), mark it dirty:
# ERL_NIF_DIRTY_JOB_CPU_BOUND or ERL_NIF_DIRTY_JOB_IO_BOUND

Enter fullscreen mode Exit fullscreen mode

Understanding this explains why some Elixir libraries that wrap C code (image processing, certain crypto operations, database drivers with native extensions) can introduce latency spikes that seem inconsistent with the BEAM's concurrency model. They are bypassing the model.

The Scheduler's Relationship With IO

IO in the BEAM is non-blocking at the scheduler level. When a process does a network read or a file operation, the BEAM does not block the OS thread. It suspends the process, registers the IO operation with an internal polling mechanism (built on epoll or kqueue depending on the OS), and runs other processes. When the IO completes, the process is rescheduled.

This is why Elixir handles tens of thousands of concurrent connections without a thread-per-connection model. Each connection maps to a process. Each process consumes a BEAM process worth of resources (a few kilobytes), not an OS thread. The IO multiplexing is handled by the runtime, not by the application code.

# Each of these connections is a lightweight process
# The BEAM handles the IO multiplexing
{:ok, socket} = :gen_tcp.accept(listen_socket)
pid = spawn(fn -> handle_connection(socket) end)

Enter fullscreen mode Exit fullscreen mode

Phoenix handling millions of concurrent WebSocket connections is not a framework trick. It is the BEAM's process model applied to network IO with no special configuration required.

What This Means for How You Write Code

Once you understand the BEAM's process model, certain Elixir patterns stop looking like conventions and start looking like direct expressions of the runtime's capabilities.

Spawning a process per request is not wasteful, it is appropriate. Letting a process crash instead of handling every possible error is not lazy, it is correct: the process's isolated heap disappears cleanly, the supervisor restarts it in a known good state, and no other process was affected.

The things that are expensive in other runtimes (concurrency, isolation, failure recovery) are cheap in the BEAM because the runtime was built to make them cheap. The things that are expensive in the BEAM (large message copies, long-running NIFs) are expensive because they work against the model.

The more directly your code expresses the model, the more you get out of it.

Further Reading