我有一个过程,一段时间后,调用mprotect()
失败并显示ENOMEM
. 该错误是由“无法分配内部内核结构”引起的:此时,该文件/proc/<pid>/maps
包含 65531 行,这当然是可疑的接近 2^16。
该过程首先使用 mmap (1280MB, MAP_PRIVATE | MAP_ANONYMOUS) 获取一块内存,然后mprotect()
在单个页面(或少量页面)上调用以启用和禁用对它们的访问,以进行调试。1280MB 映射区域最初显示为 中的一行/proc/<pid>/maps
,但每次调用mprotect()
都可能将该区域“拆分”为三部分:之前的内存、修改后的页面和之后的内存。经过多次更改,当两个相邻(但独立修改)的内存区域最终具有相同的访问标志时,通常会再次合并它们,因此总行数保持合理。
但只是“通常”。在失败的情况下,/proc/<pid>/maps
最终会产生大量具有相同保护的连续内存区域,我不明白为什么它们不合并。在单页示例中,它们被正确合并。什么时候它的工作方式不同,为什么?
作为参考,失败的程序是多线程的,尽管这不应该产生影响(对于每个线程,/proc/<tid>/maps
文件都是相同的)。见于 Linux 内核“2.6.35-30-generic #56-Ubuntu SMP”和“3.2.0-37-generic #58-Ubuntu SMP”。
编辑:如何重现:
hg clone https://bitbucket.org/pypy/stmgc
cd stmgc/c4
hg up d4e3aac8c458 # branch copy-over-original2
make debug-demo2
gdb ./debug-demo2 # lots and lots of colored output
它应该失败err = mprotect(..); assert(err == 0);