Interview Prep Zoneby CuriouserLabs

Question 3 of 5 · staff level

How does the OS create a process? Explain fork/exec and copy-on-write.

🎤 Say this first

Unix splits creation in two: fork() clones the calling process (same code, data, FDs — child returns 0, parent gets the child's pid); exec() then replaces the process image with a new program, keeping the pid and (by default) open FDs. Fork would be ruinously expensive if it copied memory — so it copies only page tables, marking pages read-only in both: copy-on-write. Only when either side writes a page does the kernel copy that one page. The gap between fork and exec is where shells set up redirection — the design's quiet genius.

The full picture

The idiom every shell is built on
pid_t pid = fork();               // clone: page tables copied, pages COW-shared
if (pid == 0) {                    // --- child ---
    dup2(logfd, STDOUT_FILENO);    // redirect stdout BEFORE exec (the gap!)
    execvp("sort", argv);          // replace image; pid and FDs survive
    _exit(127);                    // only reached if exec failed
} else {                           // --- parent ---
    waitpid(pid, &status, 0);      // reap; else the child becomes a zombie
}
  • COW mechanics: shared pages marked read-only → a write traps → kernel copies that page, remaps, resumes. Fork cost becomes proportional to page-table size, not memory size.
  • The big-process fork problem: fork from a 30GB JVM briefly needs to copy huge page tables and risks memory spikes if the child dirties pages — why Redis's fork-based snapshots need headroom, and why posix_spawn/vfork exist for fork-then-exec-immediately cases (Java's ProcessBuilder uses posix_spawn by default on Linux).
  • Zombies & orphans: exited-but-unreaped children keep their PCB (zombie) until the parent wait()s; orphans get re-parented to init. A zombie leak is a missing-wait bug, not a memory leak.
  • FD_CLOEXEC matters: FDs survive exec by default — leaking a listening socket into a child is a classic 'port already in use after restart' mystery.

🔄 Likely follow-up questions

  • Why is fork from a multithreaded process dangerous? (only the calling thread survives; locks may be held)
  • How does overcommit + COW lead to the OOM killer visiting later?
  • What does 'fork bomb' protection look like? (ulimits, cgroup pids controller)