堆栈内存如何增加?

时间:2010-07-09 10:06:22

标签: process operating-system stack

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

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

3 个答案:

答案 0 :(得分:2)

使用了许多不同的方法,具体取决于操作系统(Linux实时与正常)以及下面的语言运行时系统:

1)动态,按页面错误

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

2)固定大小

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

3)pagewise,spaghetti和类似的

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

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

编辑:拼写错误

答案 1 :(得分:0)

给定流程的堆栈具有有限的固定大小。您(理论上)无法添加更多内存的原因是因为堆栈必须是连续的,并且它会向堆增长。因此,当堆栈到达堆时,不可能进行扩展。

用户程序的堆栈大小不是由内核决定的。内核堆栈大小是内核的配置选项(通常为4k或8k)。

编辑:如果您已经知道这一点,并且只是在谈论为进程分配物理页面,那么您已经完成了该过程。但是没有必要像这样跟踪“堆栈大小”:堆栈中没有可分页条目的虚拟页面只是正常的过度使用的虚拟页面。物理内存将在首次访问时授予。但是内核 没有过度使用内存,因此在首次加载可执行文件时,堆栈可能会有完整的物理实现。

答案 2 :(得分:0)

堆栈只能使用一定长度,因为它在内存中具有固定的存储容量。如果您的问题要求堆栈正在用完的方向?答案是向下的。它在内存中向堆填充。堆是一个动态的内存组件,根据您对数据存储的需求,它可以从下到上实际增长。

enter image description here