在
Linux中,当进程从系统请求某些(虚拟)内存时,它只是在vma(进程的虚拟内存的描述符)中注册,但是在调用时不保留每个虚拟的物理页面.稍后,当进程将访问此页面时,它将出现故障(访问将生成Page Fault中断),PF#handler将分配物理页面和更新进程页面表.
有两种情况:读取时的故障可能变为写入保护的零页面(特殊全局预归零页面)的链接;写入错误(无论是在零页面上还是在刚刚需要但未物理映射的页面上)都将导致实际的私有物理页面分配.
对于mmaps(和brk / sbrk,也是内部mmap),这个方法是每页;所有mmaped区域都在vma中注册为整体(它们具有开始和结束地址).但堆栈是以其他方式处理的,因为它只有起始地址(在典型平台上较高的地址;增长到较低地址).
问题是:
当我在堆栈附近访问新的未分配内存时,它将获得PF#并且增长.如果我不访问堆栈旁边的页面,而是访问堆栈10或100页的页面,这种增长如何处理?
例如.
int main() { int *a = alloca(100); /* some useful data */ int *b = alloca(50*4096); /* skip 49 pages */ int *c = alloca(100); a[0]=1; /* no accesses to b - this is untouched hole of 49 pages */ c[0]=1; }
该程序是否会为堆栈分配2或50个私有物理页面?
我认为要求内核在单个页面故障中分配数十个物理页面然后进行逐页分配的数十个页面故障是有利可图的(1个中断1上下文切换简单,缓存友好的循环遍历N个页面分配请求与N个中断N上下文 – 当mm代码可以从Icache中逐出时,切换N页分配.