在Linux上,这里给出了确切的机制:在处理匿名映射上的页面错误时,您检查是否属于“增长分配”,应该像堆栈一样扩展。如果VM区域记录表明您应该这样做,则可以调整起始地址以扩展堆栈。
当发生页面错误时,根据地址,可以通过堆栈扩展对其进行服务(并消除错误)。虚拟内存的这种“在故障时向下增长”的行为可以由任意用户程序请求,并将MAP_GROWSDOWN
标志传递给mmap
syscall。
您也可以在用户程序中使用此机制:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
int main() {
long page_size = sysconf(_SC_PAGE_SIZE);
void *mem = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_GROWSDOWN|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
if (MAP_FAILED == mem) {
perror("failed to create growsdown mapping");
return EXIT_FAILURE;
}
volatile char *tos = (char *) mem + page_size;
int i;
for (i = 1; i < 10 * page_size; ++i)
tos[-i] = 42;
fprintf(stderr, "inspect mappping for originally page-sized %p in /proc... press any key to continue...\n", mem);
(void) getchar();
if (munmap(mem, page_size))
perror("failed munmap");
return EXIT_SUCCESS;
}
出现提示时,您可以找到该程序的pid(通过ps
),然后查看/proc/$THAT_PID/maps
原始区域的增长情况。
ulimit -s
)。