不能直接用 clock() 或 std::chrono::steady_clock 测 fork(),因 clock() 返回毫秒级 CPU 时间且父子进程独立计数,steady_clock 在 fork 瞬间不保证读数同步;正确做法是用 clock_gettime(CLOCK_MONOTONIC, ...) 在同一进程上下文 fork 前后打点,取纳秒级差值,并重复测量取中位数。

为什么不能直接用 clock() 或 std::chrono::steady_clock 测 fork()?
因为 fork() 创建子进程后,父子进程各自拥有独立的时间计数器,clock() 返回的是进程 CPU 时间(CLOCKS_PER_SEC 精度通常只有毫秒级),而 std::chrono::steady_clock 虽然高精度,但父子进程的时钟读数在 fork 瞬间并不“同步”——内核只复制时间源状态,不保证读数一致。你测到的很可能是子进程启动后的延迟,而非 fork 本身开销。
正确做法:用 clock_gettime(CLOCK_MONOTONIC, ...) + 自旋校准
必须在 fork 前后**同一进程上下文**中获取单调时钟,且避免系统调用干扰测量。关键点:
- 使用
clock_gettime(CLOCK_MONOTONIC, &ts),它开销小(通常由 vDSO 提供,无需陷入内核) - fork 前后各调一次,差值即为 fork 耗时(纳秒级)
- 为排除 cache/TLB 颠簸影响,建议重复测量 100–1000 次取中位数
- 务必在 fork 后让子进程立即退出(
exit(0)),否则子进程继续运行会污染父进程的后续测量
示例片段:
struct timespec ts1, ts2; clock_gettime(CLOCK_MONOTONIC, &ts1); pid_t pid = fork(); clock_gettime(CLOCK_MONOTONIC, &ts2); if (pid == 0) exit(0); // 子进程立刻退出 long ns = (ts2.tv_sec - ts1.tv_sec) * 1000000000L + (ts2.tv_nsec - ts1.tv_nsec);
实测耗时受哪些因素影响最大?
fork 耗时不是固定值,主要被以下三类因素拖慢:
立即学习“C++免费学习笔记(深入)”;
-
/proc/sys/vm/overcommit_memory设置为 2 时,内核需检查内存是否足够(即使没实际分配),可能触发页表扫描 —— 这是常见瓶颈 - 父进程虚拟地址空间越大(尤其是大量 mmap 区域),fork 时需复制或 COW 标记页表项越多,耗时线性增长
- 启用 SMAP/SMEP 的 CPU 上,内核需刷新 TLB 条目,尤其在多核 NUMA 系统上更明显
可临时用 echo 1 > /proc/sys/vm/overcommit_memory 测试纯 copy-on-write 场景下的最小开销(通常 1–5 微秒)。
别踩这个坑:用 getrusage(RUSAGE_SELF, ...) 测 fork 不靠谱
getrusage 返回的是进程累计资源使用,ru_stime 和 ru_utime 是 fork 后父子分别累加的,无法反推 fork 瞬间开销。更糟的是,某些内核版本在 fork 时会重置部分字段,导致差值为负或归零。实测中它常给出 0 或抖动极大的结果,完全不可信。
真正要测系统调用开销,就得紧贴 syscall 入口和返回点,用最轻量的时钟打点 —— 其他任何间接方式都会引入噪声或逻辑错误。


















