涉及堆栈和堆分配的系统调用

涉及堆栈和堆分配的系统调用

在进程地址空间中,有栈和堆。当调用函数时,甚至声明局部变量时,它都会使用堆栈;内核必须分配物理地址并创建虚拟地址到物理地址的映射;那么,这里应该涉及到一个系统调用,这是怎么回事呢?

Linux 中的堆栈分配是如何工作的?

第一个答案说:“我发现堆栈在没有任何系统调用的情况下增长(根据 strace)。因此,这意味着内核自动增长它(这就是上面的“隐式”含义),即没有显式 mmap /mremap 来自进程。”如果“增长”堆栈是内核的工作,为什么不涉及系统调用?

堆什么时候用于动态内存分配?

对于堆,第一个答案说:“如果对 malloc 的调用可以通过重用来满足,那么对 malloc 的调用不一定会导致对 sbrk 或 mmap 的调用(取决于 Libc 如何实现动态内存分配)来扩展映射”先前释放的内存区域。”我想这就是空闲列表的概念。堆栈分配是否使用相同的概念?

我对这两种分配的基本不满是必须分配物理内存,并且必须创建从 VMA 到物理的映射,因此应该发生系统调用。我尝试阅读第一个问题答案中链接的梅尔·戈尔曼所著的书,但找不到任何有意义的内容来回答我的问题。

答案1

当进程尝试向堆栈底部写入数据时,内核会增加堆栈以响应触发的页面错误。这不会显示为系统调用。

系统调用并不是内核参与的唯一方式:它还处理错误和中断。

答案2

几乎您提到的所有内容都与虚拟内存无关。虚拟内存是同时、独立发生的。除了增加堆栈之外。

当堆栈溢出时,内核可以增长堆栈。这可以通过内核将堆栈之外的页面设置为不存在来完成。当进程尝试访问超出库存末尾时,它会读取或写入此不存在的页面,从而导致页面错误。然后,内核分配更多内存并将其映射到该页面(可能还有更多页面),并将一个新的不存在页面放置在新末尾之外。

处理页面错误和处理系统调用几乎完全相同,并且具有相同的成本。除用户态进程外,不需要任何特殊指令。这使得速度更快,因为大多数时候没有页面错误。

系统调用使用trap(确切的指令取决于处理器指令集)指令。trap指令、除零、中断、页面错误和其他一些事情都以相同的方式处理。

相关内容