ELF可执行文件.data段数组访问无Major页故障的原因问询
问题:为何访问.data段数组未触发Major页故障?
我预期以下程序在访问数组x的部分内容时会触发Major页故障——注意该数组不在.bss段而在.data段。
#include <unistd.h> #define C (256*1024*1024) char x[C] = { 1 }; int main(void) { char c; read (STDIN_FILENO, &c, 1); for (int i = 1024; i < C; i += 1024) { x[i] = x[i] - 1; x[i - 1024] = x[i]; } }
编译后可见数组x确实在可执行文件中:
$ gcc a.c; ls -l a.out -rwxr-xr-x. 1 mcadilha domain users 257M Jan 20 20:49 a.out
但/usr/bin/time的报告与预期不符:未进入主循环时,Major页故障为0,仅少量Minor页故障;进入主循环后,Major页故障仍为0,Minor页故障为65593。我尝试将x填充为随机值,结果无变化。请问:为何未产生任何Major页故障?
原因分析
- Major页故障的本质:Major页故障只有在需要从磁盘直接读取数据到物理内存时才会触发;而Minor页故障是指数据已经存在于系统的页缓存中,只需建立虚拟内存到物理内存的映射,不需要额外的磁盘IO。
- 可执行文件的映射逻辑:当程序加载时,操作系统会把可执行文件的.data段映射到进程虚拟地址空间,但不会立即加载所有数据到物理内存。不过,操作系统会维护页缓存——可执行文件本身存储在磁盘上,系统在处理程序加载请求时,会把文件内容预读到页缓存里,或者在第一次访问时先从磁盘读入缓存。
- 你的程序的实际执行流程:当主循环访问数组x的页面时,这些页面的数据已经在页缓存中存在了,操作系统只需要完成虚拟页到缓存物理页的映射,所以只会触发Minor页故障,不会产生Major页故障。
- 填充随机值无影响的原因:不管数组初始化内容是固定值还是随机值,只要可执行文件生成后被正确映射,其内容都会被操作系统纳入页缓存管理,后续访问时依然不需要从磁盘重新读取,自然不会出现Major页故障。
内容的提问来源于stack exchange,提问作者Michaël
相关产品推荐
相关产品推荐

