process - 堆栈内存如何增加?

标签 process operating-system stack

在典型的 C 程序中,linux 内核提供 84K - ~100K 的内存。当进程使用给定内存时,内核如何为堆栈分配更多内存。

IMO 当进程占用堆栈的所有内存并现在使用下一个连续内存时,理想情况下它应该页面错误,然后内核处理页面错误。
是不是内核为给定的进程提供了更多的内存给堆栈,linux内核中哪个数据结构标识了进程的堆栈大小??

最佳答案

有许多不同的方法使用,具体取决于操作系统(linux 实时与普通)和下面的语言运行时系统:

1) 动态的,通过页面错误

通常将一些实际页面预分配给更高的地址,并为其分配初始 sp。栈向下增长,堆向上增长。如果页面错误发生在堆栈底部下方,则会分配并映射丢失的中间页面。有效地从顶部到底部自动增加堆栈。通常有一个最大值来执行这种自动分配,它可以或不能在环境 (ulimit)、exe-header 中指定,或者由程序通过系统调用 (rlimit) 动态调整。尤其是这种可调整性在不同操作系统之间差异很大。通常也有一个限制,即距离堆栈底部“多远”一个页面错误被认为是正常的并且自动增长发生。请注意,并非所有系统的堆栈都向下增长:在 HPUX 下(使用过?)向上增长,所以我不确定 PA-Risc 上的 linux 是做什么的(有人可以对此发表评论)。

2) 固定尺寸

其他操作系统(尤其是在嵌入式和移动环境中)或者根据定义具有固定大小,或者在 exe 头文件中指定,或者在创建程序/线程时指定。特别是在嵌入式实时 Controller 中,这通常是一个配置参数,并且单个控制任务获得固定堆栈(以避免失控线程占用更高优先级控制任务的内存)。当然,在这种情况下,内存可能只会虚拟分配,直到真正需要。

3) pagewise, spaghetti 和类似的

这种机制往往被遗忘,但仍在某些运行时系统中使用(我知道 Lisp/Scheme 和 Smalltalk 系统)。这些根据需要动态分配和增加堆栈。但是,不是作为单个连续段,而是作为多页块的链接链。它需要编译器生成不同的函数进入/退出代码,以便处理段边界。因此,此类方案通常由语言支持系统而不是操作系统本身实现(曾经是更早的时代 - 叹气)。原因是当你在交互环境中有很多(比如 1000 个)线程时,预分配 1Mb 只会填满你的虚拟地址空间,你不能支持一个以前未知单个线程的线程需求的系统(这是通常是在动态环境中的情况,在这种情况下,用户可能会将 eval-code 输入到单独的工作区中)。所以上面的方案 1 中的动态分配是不可能的,因为会有其他线程使用它们自己的堆栈。堆栈由较小的段(例如 8-64k)组成,这些段从池中分配和释放,并链接到堆栈段链中。这种方案也可能需要对延续、协程等事物的高性能支持。

现代 unixes/linuxes 和(我猜,但不是 100% 确定)windows 使用方案 1)作为 exe 的主线程,和 2)用于附加(p-)线程,这需要线程创建者给出的固定堆栈大小最初。大多数嵌入式系统和 Controller 使用固定(但可配置)的预分配(在许多情况下甚至是物理预分配)。

编辑:错字

关于process - 堆栈内存如何增加?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3211600/

相关文章:

android - 为什么在 Intent 重定向代码之后执行代码?

c# - 获取带有扩展名的进程名称(每个示例为 .exe)

bash - 如何在 bash 中等待多个子进程完成,并在任何子进程以代码 !=0 结束时返回退出代码 !=0?

linux - 同一个进程的线程可以跑在不同的核上吗?

c - 不同步冲洗

c - 一堆字符串

c++ - 评估中缀表达式而不将其转换为后缀

c# - Windows XP 的 .NET 进程问题

function - 为什么要在函数开头保存旧的基指针?

python - 通过迭代指定的数据帧值来创建新目录 Python Pandas Numpy