【问题标题】:Stack memory management in LinuxLinux中的堆栈内存管理
【发布时间】:2015-09-28 11:16:28
【问题描述】:

我有几个关于 Linux 堆栈大小限制的问题。我对 x86_64 系统最感兴趣,但如果存在平台差异,我也想了解它们。我的问题是:

1) Linux 如何动态增加栈的大小?

我编写了一个带有递归函数(使用堆栈空间)的测试程序,我可以在其中将迭代次数指定为命令行参数。程序在完成递归后暂停等待用户输入,这使我可以获取有关正在运行的进程的信息。如果我运行少量迭代,然后使用pmap 查看堆栈大小,则为 132K。

00007fff0aa3c000    132K rw---   [ stack ]

而如果我运行大量迭代,大小可能会变得更大,我相信默认情况下最多 8192 KB。例如,这里是运行更多迭代的输出。

00007fff3ed75000   8040K rw---   [ stack ]

但是如果我在运行应用程序时使用strace 来跟踪系统调用,我看不到任何与增加堆栈相关的内容。所以我想知道内核正在做什么来管理进程的堆栈空间。

2) Linux 在设置ulimit -s unlimited 时是否以任何方式保护堆栈区域?

如果我使用命令ulimit -s unlimited,那么我可以运行我的递归函数的更多迭代并且堆栈变得更大。例如这里是 pmap 的输出

00007ffda43a3000 8031260K rw---   [ stack ]

因为我不想让我的机器崩溃/挂起/锁定,所以我还没有测试过无限递归。但我想知道我是否做了任何会导致内核检测堆栈溢出的事情。还是 ulimit 是唯一的保护,关闭它可以让堆栈无限增长?

3) 如何处理堆栈保护页面?

这与我尝试过的任何东西都没有直接关系,但我也想知道 Linux 如何管理堆栈保护页面以及允许堆栈动态增长。

【问题讨论】:

标签: linux memory-management stack-overflow


【解决方案1】:
  1. 对于每个正在运行的进程,Linux 都会保留一个虚拟内存地址区域列表。如果地址引用产生页面错误,Linux 会检查该列表以查看虚拟地址是否合法(在某个区域的范围内)。如果没有被区域声明,应用程序会收到一个 SIGSEGV 错误,否则内核会分配另一页系统内存并添加到转换缓存中。如果错误地址只是错过了一个区域,并且该区域用于堆栈(根据机器架构,堆栈会向上或向下增长),那么 Linux 会分配另一个 VM 页面,将其映射到该区域,从而增大堆栈。
  2. 内核不保护堆栈。如果堆栈访问由于物理 VM 页面未附加到进程的内存区域而导致页面错误,则会测试进程的 rlimit 以查看是否允许添加另一个页面。
  3. 某些 malloc(3) 调试器库正在使用堆栈保护页面。这些是将每个内存请求扩展 2 个 VM 页面:新页面前一页,新页面后一页。额外的页面被标记为根本无法访问,因此如果应用程序离开区域的末尾或在开始之前移动,则应用程序会遇到访问冲突。

以上内容被无耻地过度简化了,但仍然应该给出要点。

【讨论】:

  • 关于(2),内核如何确定它是否正在增长堆栈?它是否检查添加新页面是否与现有堆栈连续,并且只有在这种情况下才会增加堆栈区域以包含此页面?
  • 究竟什么才算“在某一区域范围内”?
猜你喜欢
  • 2012-03-07
  • 1970-01-01
  • 2020-10-10
  • 2017-04-28
  • 1970-01-01
  • 2016-04-05
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
相关资源
最近更新 更多