Compare
Side-by-side on the decisions that recur: process vs thread, threads vs async, mutex vs semaphore, blocking vs non-blocking I/O, container vs VM — with when to choose each.
Process vs ThreadThreads vs Async / event loopConcurrency vs ParallelismMutex vs SemaphoreBlocking I/O vs Non-blocking / async I/Oselect / poll vs epoll / kqueueContainer vs Virtual machineStack vs HeapPipe vs Shared memoryOS page cache vs Application cache
| Container | Virtual machine | |
|---|---|---|
| Kernel | Shares the host kernel (uname -r matches the host) | Boots its own kernel on virtual hardware from a hypervisor |
| Isolation mechanism | Namespaces (PID, net, mount, user…) and cgroups — kernel features | Hardware virtualisation (VT-x/AMD-V): the guest cannot see the host at all |
| Start time and footprint | Milliseconds; MBs — it is just a process tree with a different view | Seconds; hundreds of MBs to GBs for a whole OS image |
| Security boundary | One kernel bug can cross it; user namespaces and seccomp narrow the surface | Much stronger; VM escapes are rare and severe |
| Different OS inside | No — Linux containers need a Linux kernel (Docker Desktop runs a Linux VM on macOS/Windows; Windows containers need a Windows host) | Yes — any guest OS the hypervisor supports |
| Resource limits | cgroups: CPU weight, memory limit (page cache counts), PIDs, I/O | Fixed vCPUs and RAM assigned at boot; ballooning to adjust |
| Middle ground | gVisor, Kata, Firecracker micro-VMs: container UX with a VM boundary | — |
| Choose this when | Packaging and density for your own trusted services: fast start, many per host, one kernel is fine. | Untrusted tenants, a different kernel or OS, kernel modules, or compliance that demands a hardware boundary. |