我正在考虑阅读/ proc / self / maps找到标记为[stack]的行,以获取我的进程的堆栈的开始和结束地址.思考这个解决方案让我有以下几个问题:
> / proc / self / maps为我的特定进程显示一个132k的堆栈,堆栈的最大大小(ulimit -s)在我的系统上是8兆. Linux如何知道由于我们超出堆栈限制而发生的给定页面错误属于堆栈(并且堆栈必须更大),而不是我们到达进程的另一个内存区域?
> Linux是否缩小了堆栈?换句话说,例如从深度函数调用返回时,OS是否减少与堆栈对应的虚拟内存区域?
> OS最初为堆栈分配了多少虚拟空间?
>我的解决方案是否正确,还有其他更清洁的方法吗?
解决方法
在进程执行时,内核选择一个默认的堆栈顶部(例如,传统的i386 arch是0xc0000000,即虚拟地址空间的用户模式区域的结尾).
可执行格式(ELF vs a.out等)的类型可以在理论上改变初始堆栈顶部.然后完成任何额外的堆栈随机化和任何其他修复(例如,当使用时,vdso [系统调用跳板]区域通常放在这里).现在你有一个实际的最初的堆栈.
内核现在分配任何空间来构建参数和环境向量等,以便进程,初始化堆栈指针,创建初始寄存器值,并启动进程.我相信这提供了(3)的答案:即内核只分配足够的空间来包含参数和环境向量,其他页面按需分配.
其他答案,尽可能的告诉我:
(1)当进程尝试将数据存储在堆栈区域当前底部下方的区域时,会产生页面错误.内核故障处理程序确定进程的虚拟地址空间中的下一个填充的虚拟内存区域的开始位置.然后看看是什么类型的区域.如果它是一个“成长中”区域(至少在x86上,所有堆栈区域都应该被标记为下降),并且如果故障时进程的堆栈指针(ESP / RSP)值小于该区域,如果进程没有超过ulimit -s设置,并且该区域的新大小将不会与另一个区域冲突,那么它被认为是增加堆栈的有效尝试,并且分配额外的页面以满足的过程.
(2)不是100%确定,但我不认为有任何企图缩小堆积区域.如果真的没有被重新使用,大概会执行正常的LRU页面扫描,使现在未被使用的区域成为寻呼到调换区域的候选区域.
(4)您的计划对我来说似乎是合理的:/ proc / NN / maps应该得到整个堆栈区域的起始和结束地址.我认为这将是你的堆栈中最大的.当前的实际工作堆栈区域OTOH应位于当前的堆栈指针和区域的末尾之间(通常没有什么应该使用堆栈指针下面的堆栈区域).