测试fork的CoW机制时后续内存访问变慢,是否由fork拷贝导致?
结论
是的,你观测到的性能下降确实和fork的写时复制(CoW)机制直接相关,本质是fork后父进程首次写入共享内存页时触发的大量内核态开销导致的。
具体原因分析
你的测试代码存在非常典型的CoW压力特征:定义的每个结构体大小为(1+1023)*4字节 = 4KB,正好匹配x86平台默认的内存页大小,数组总共有262144个元素,对应262144个独立的内存页,总占用内存1GB。
启用fork逻辑后,系统的执行流程和开销如下:
- fork调用阶段:操作系统不会直接拷贝1GB的物理内存,仅会复制父进程的页表给子进程,同时将所有共享物理页的访问权限设置为只读,父子进程共享同一份物理内存。
- 子进程直接调用
_exit(0)退出,没有修改任何共享页,但父进程后续的写入操作会触发连锁开销:
后续遍历数组修改每个元素的n值时,每修改一个元素就对应修改一个独立的内存页,此时因为该页还是只读的共享页,会立刻触发写时复制缺页异常,每一次异常内核都要完成以下操作:- 分配新的物理页,将原共享页的4KB数据拷贝到新页
- 更新父进程的页表项,指向新的物理页,修改访问权限为可写
- 刷新对应虚拟地址的TLB(地址翻译缓存),保证地址翻译正确性
没有fork逻辑时,所有内存页已经是可写状态,写入操作仅需要用户态操作,命中TLB即可完成,没有任何内核态切换和额外操作的开销,所以耗时仅5ms左右。开启fork后,你总共要处理26万+次缺页异常,所有异常的内核态处理时间累加起来,就出现了你观测到的20倍左右的性能差距。
补充说明:你使用的
clock()统计的是进程的总CPU时间,包含用户态和内核态的CPU耗时,所以缺页异常的内核处理时间会被完整统计到最终的耗时结果中。
内容的提问来源于stack exchange,提问作者l4m2
相关产品推荐
相关产品推荐

