关于/proc/$pid/maps文件未呈现地址的状态及VM相关问询
嘿,我来帮你把这些VM相关的疑问拆解开讲清楚~
一、/proc/$pid/maps里没出现的地址是什么状态?
/proc/$pid/maps里没列出来的虚拟地址,绝大多数都是unallocated virtual pages。简单说就是内核根本没给这些地址创建任何页表项,它们不属于进程的有效虚拟地址空间——要是进程敢访问这类地址,直接就触发段错误(SIGSEGV)了。
有没有例外?几乎没有。只要是内核给进程分配过的虚拟内存区域(不管是文件映射、匿名映射,还是栈/堆这种特殊区域),都会老老实实出现在maps里。没出现的就意味着这个地址范围完全没被内核“认领”,属于未分配状态。
二、Allocated和Unallocated Pages到底是什么?什么时候分配?
先把这两个核心概念掰明白:
- Unallocated virtual pages:内核没为这些虚拟地址建立任何页表项,它们不在进程的合法地址范围内。进程碰它们=找死(段错误)。
- Allocated virtual pages:内核已经给这些虚拟地址建了页表项(哪怕页表项标记着“还没对应物理页”),属于进程的合法地址空间。当进程第一次访问这类页面时,会触发缺页异常,内核再去分配物理页(或者从交换区加载、从文件读内容)。
那页面什么时候会被标记为allocated?
- 文件映射(比如加载可执行文件、动态库):当你调用
mmap()创建映射的那一刻,内核就把这个虚拟地址范围标记为allocated了,但此时并没有分配物理页——直到进程第一次访问其中某个地址,触发缺页异常才会真正分配物理页并缓存内容。 - 匿名映射(比如堆、匿名mmap):同样是调用
mmap()(或者堆扩展时用的brk()/sbrk())时,内核就把虚拟地址标记为allocated,物理页也是按需分配,第一次访问才会落地。 - 栈:进程刚创建时,内核就给栈分配好了虚拟地址范围(属于allocated),但物理页也是随栈的增长按需分配——当栈向下延伸到新的页时,触发缺页异常才会分配对应的物理页。
三、栈和堆属于哪类页面?
栈和堆都属于allocated virtual pages,但这里要注意:这里的“allocated”指的是虚拟地址已经被内核纳入进程的有效地址空间(有对应的页表项),不是说已经分配了物理页。
举个直观的例子:进程刚启动时,堆的初始虚拟地址范围已经能在maps里看到,但此时只有很少的物理页被实际分配;当你用malloc()申请更大的内存,堆扩展时,内核会把新的虚拟地址范围标记为allocated,但物理页还是要等你第一次读写这些地址时才会被分配。栈也是一样的道理,初始虚拟范围是合法的,但物理页随用随分配。
另外你提到的《CS:APP》里的三类页面:
- unallocated:就是上面说的完全没被内核认领的地址;
- allocated but not cached:虚拟地址已分配(有页表项),但还没有对应的物理页(或者物理页被交换到磁盘了),访问会触发缺页;
- allocated and cached:虚拟地址已分配,且有对应的物理页缓存,访问直接命中,不会触发缺页。
至于/proc/$pid/maps确实不会显示页面是否被缓存——这属于内核物理页管理的细节,用户态没法直接拿到完整的缓存状态,哪怕用pmap -x这类工具,也只能看到部分物理页分配情况,没法完全体现缓存状态。
内容的提问来源于stack exchange,提问作者youwin2152

