流程的虚拟地址空间以流程的text
,data
和bss
段开头。放置此堆分配后,堆会增大到更大的内存地址。但是,在使用堆的一部分之前,必须分配一个内存块(valloc
等),否则会发生(或应该发生)segfault
。
堆栈从虚拟地址空间中的初始大地址向较小的值增长。据我所知,这没有虚拟内存分配。如果没有先前的内存分配,如何在堆不可能的情况下使用堆栈呢? (它的线性虚拟地址空间相同。)
据我所知,alloca
的实施方式与sub esp, <size>
一样。但是堆栈正在使用的虚拟地址空间区域必须在此之前以某种方式分配,对吧?
答案 0 :(得分:1)
以某种方式 段错误。这是一种“懒惰”的优化。操作系统尽可能地作弊,只要差异不是外部可观察的。
但是,陷阱不会像正常的段错误那样导致生成信号(默认情况下会导致进程崩溃)。相反,操作系统会验证是否未超出允许的线程大小,然后从零池中提取新页面。
在Windows下,该机制被称为“保护页面”,我不知道在Linux下有类似的命名。无论哪种方式,保护页面在技术上只是一个写保护页面(或不存在的页面),操作系统将其记为“特殊”,因此触摸时可能会发生某些特定操作。
这与动态分配(malloc
,调用sbrk
)的工作方式非常相似。分配内存时,只要不访问分配的内存,就不会发生太多事情。唯一发生的事情是操作系统“记得”你增长了数据段
如果现在发生故障,操作系统将创建页面,或者分别从零池中拉出它,并假装它一直在那里。你永远不会知道它不存在。