如何让页面在下次访问时触发页错误?含多系统及ARM方案问询
测试SVE避错加载重试路径的可靠方案
Linux 平台方案
匿名页/文件页回收(最可靠,无需交换空间)
利用mmap创建映射后,通过madvise(MADV_DONTNEED)强制内核回收页面,后续访问必然触发主缺页错误:#include <sys/mman.h> #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { // 方案1:匿名页(回收后访问会得到零页) void *anon_page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (anon_page == MAP_FAILED) { perror("mmap anon"); return 1; } madvise(anon_page, 4096, MADV_DONTNEED); // 强制回收页面 // 方案2:文件映射(回收后访问会从磁盘加载原数据) int fd = open("/tmp/test_page", O_RDWR | O_CREAT | O_TRUNC, 0644); ftruncate(fd, 4096); void *file_page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); memset(file_page, 'x', 4095); ((char*)file_page)[4095] = '\0'; msync(file_page, 4096, MS_SYNC); // 确保数据落盘 madvise(file_page, 4096, MADV_DONTNEED); // 回收内存中的页面 // 此时访问上述任意页面都会触发主缺页错误 return 0; }MADV_DONTNEED在Linux上行为明确:立即回收指定页面,匿名页重置为零页,文件页从内存移除,无需依赖交换空间。验证页面状态
用mincore确认页面是否已被回收,保证测试环境符合预期:unsigned char in_core[1]; if (mincore(anon_page, 4096, in_core) == 0) { // in_core[0] & 1 为1表示页面在内存,0表示已被回收 }
FreeBSD 平台方案
- 通用页面回收
使用madvise(MADV_DONTNEED),行为与Linux一致:匿名页回收后访问返回零页,文件页回收后从磁盘重新加载,无需交换空间即可触发缺页。 - 显式页换出
若需保留匿名页数据,可使用madvise(MADV_PAGEOUT),要求内核将页面换出到交换空间,后续访问触发缺页并重新加载原数据。该调用在有交换空间时行为可靠,无交换空间时仅对文件页有效。
通用/硬件无关测试技巧
- 构造跨页测试场景
为模拟字符串跨页触发避错的情况:- 映射连续两页内存,第一页填充满非NUL字符(如
'a') - 第二页用上述方法回收,且在第二页起始位置写入NUL字符
此时用SVE避错加载指令读取跨页字符串时,会在访问第二页时触发避错,进入重试路径;用常规加载指令访问第二页则会触发缺页,内核处理后加载到NUL字符,完成正常逻辑。
- 映射连续两页内存,第一页填充满非NUL字符(如
- 规避未定义行为
不要依赖内核的延迟页分配(直接访问新映射的匿名页),这种行为受内核配置影响,必须用显式madvise调用确保页面被回收。
ARM SVE 特定测试注意事项
- 读取FPSR寄存器的
FZC位,判断是否触发了避错加载 - 重试路径中使用常规加载指令(如
LD1B)替代避错加载指令,确保触发缺页错误并让内核处理
内容的提问来源于stack exchange,提问作者fuz
相关产品推荐
相关产品推荐

