【问题标题】:How does a stack memory increase?堆栈内存如何增加?
【发布时间】:2011-03-13 19:12:48
【问题描述】:

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

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

【问题讨论】:

标签: process operating-system stack


【解决方案1】:

根据操作系统(linux 实时与普通)和底层语言运行时系统,可以使用多种不同的方法:

1) 动态的,由于页面错误

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

2) 固定大小

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

3) pagewise, spaghetti 和类似的

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

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

编辑:错字

【讨论】:

  • 值得注意的是,Google 的 Go 语言使用的是方案 3。
  • 不再。从 1.3 开始,Go 运行时将分配一个更大的连续堆栈并将旧堆栈移入其中。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2010-10-27
      • 2012-12-06
      • 2013-12-24
      • 2011-09-29
      • 1970-01-01
      • 2011-11-27
      • 2012-07-19
      • 1970-01-01
      相关资源
      最近更新 更多