Choosing fork, vfork, or clone for Process Creation in Unix
A decision guide for picking fork, vfork, or clone in Unix-like systems, comparing overhead, memory sharing and portability with a concrete C example and validation steps using strace.
02 Sept 2025, 19:34 UTC

The decision
You need a new execution context in a Unix-like program and the choice is not just fork(). The constraints are overhead, how much memory is shared with the parent, and how portable the code must be. The practical takeaway is: use fork for portable general purpose spawning, use vfork only when the child immediately execs and you accept strict safety rules, and use clone only on Linux when you need configurable sharing for threads or lightweight processes.
Options at a glance
| Mechanism | Overhead | Memory sharing | Portability | Typical use |
|---|---|---|---|---|
| fork | Medium | Copy-on-write | High, POSIX | General purpose process creation |
| vfork | Low | None (shares) | Medium, POSIX but discouraged | Immediate exec after fork |
| clone | Low-Medium | Configurable via flags | Low (Linux) | Threads or lightweight processes |
Copy-on-write means the kernel marks parent pages read-only and duplicates them only on first write by either process. That avoids a full copy at fork time while keeping the child independent.
Trade-offs
fork provides safety and POSIX portability. The kernel duplicates page tables and uses copy-on-write for user memory. The cost is page table setup and later faults on writes. It is safe for the child to run arbitrary code before exec.
vfork avoids copying by running the child in the parent's memory space with the parent suspended until the child calls exec or _exit. Overhead is low, but the child shares the parent's stack and registers. If the child modifies data, calls non-async-signal-safe functions, or returns from the function that called vfork, behavior is undefined and can corrupt the parent. Use only for immediate exec with no intervening work.
clone is a Linux system call exposed via glibc. It lets you choose which resources are shared: virtual memory, filesystem information, signal handlers, PID namespace, etc. That granularity enables threads when memory and signals are shared, or very lightweight processes when only some resources are shared. The cost is non-POSIX portability and complex flag composition. Flags such as CLONE_VM, CLONE_FS, CLONE_SIGHAND, SIGCHLD determine the semantics.
Concrete implementation pattern
The following C skeleton lets you switch the mechanism with a compile-time define. Run it as an unprivileged user on a Linux host with gcc available.
#include
#include
#include
#include
#define USE_FORK 0
#define USE_VFORK 1
#define USE_CLONE 0
int main() {
pid_t pid;
#if USE_FORK
pid = fork();
#elif USE_VFORK
pid = vfork();
#elif USE_CLONE
pid = clone(NULL, malloc(4096), SIGCHLD, NULL, 0, 0);
#endif
if (pid == 0) {
execlp("ls", "ls", NULL);
_exit(127);
} else {
wait(NULL);
printf("Child finished\n");
}
return 0;
}Validation
To verify fork behavior, run the program under strace and look for clone(SIGCHLD) system call followed by copy-on-write page faults (segv handled by kernel). To verify vfork, check that the child's execve occurs before any return from vfork and the parent remains blocked until the child calls exec or _exit; strace will show a vfork call without an intervening mmap.
Limitations
vfork is unsafe if the child modifies data or returns before calling exec or _exit, as it shares the parent's stack and can lead to undefined behavior. clone is not part of the POSIX standard; code that relies on it will only run on Linux and may need different flags for threading versus process creation.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.