是否可以确定堆栈上有多少可用空间?

时间:2013-06-22 12:47:40

标签: c++

我正在构建一个小型软件引擎,我想使用堆栈来快速迭代大量集合。但后来我发现这可能是一个坏主意,因为堆栈不像堆那么大的内存存储。但我被堆栈的速度和缺乏动态分配编码实践所吸引。

有没有办法找出我可以在给定平台上推送堆栈的程度?我主要关注移动设备,但问题可能出现在任何平台上。

5 个答案:

答案 0 :(得分:7)

在* nix上,使用getrlimit

   RLIMIT_STACK
          The maximum size of the process stack, in bytes.  Upon
          reaching this limit, a SIGSEGV signal is generated.  To handle
          this signal, a process must employ an alternate signal stack
          (sigaltstack(2)).

在Windows上,使用VirtualQuery

  

对于第一次调用,将堆栈中任何值的地址传递给   获取已提交堆栈空间的基址和大小(以字节为单位)。   在堆栈向下增长的x86计算机上,减去大小   从基地址和VirtualQuery再次:这将给你   为堆栈保留的空间大小(假设你不是   正是在当时的堆栈大小限制上)。总结两者   自然地给你总堆栈大小。

没有独立于平台的方法,因为堆栈大小在逻辑上留给实现和主机系统 - 在嵌入式mini-SOC上,分发的资源少于128GB RAM服务器。但是,您可以使用特定于API的调用来影响所有操作系统上特定线程的堆栈大小。

答案 1 :(得分:5)

可能的便携式解决方案是自己编写分配器 您不必使用进程堆栈,只需在堆中进行模拟即可 在开始时分配大量内存,并在其上面写一个堆栈分配器,以便在分配时使用它。
有关如何在C ++中实现它的信息,请参阅Google“分配器要求”。

我不确定“Stack Allocator”这个术语是否是规范的,但我的意思是你必须对堆栈进行分配或解除分配的限制。 既然你说你的算法适合这种模式,我认为这很容易。

答案 2 :(得分:2)

在标准C ++中,绝对不是。以便携的方式,可能不是。在特定的操作系统中,有时候。如果不出意外,您可以打开自己的可执行文件大小并检查可执行文件的标头以查看它的堆栈大小。 [下一个问题当然是“在这段代码之前使用了多少堆栈” - 这可能很难确定]。

如果在单独的线程中运行代码,许多(低级别)线程接口允许您指定堆栈(或堆栈大小),例如E.g Posix线程pthread_set_stacksize或MS _beginthread。同样,在获得实际的线程代码之前,你并不确切知道已经用了多少空间 - 但它可能不是很大。

当然,在嵌入式系统(例如移动电话)中,堆栈大小通常非常小,4K,12K或64KB非常正常 - 有时甚至比某些系统中的小得多。

另一个潜在的问题是,您无法真正知道堆栈上实际使用了多少空间 - 您可以在编译系统中进行测量,当然,如果您有一个堆栈本地数组{{1我们可以知道它至少占用int array[25]; - 但可能有填充,编译器在堆栈上保存寄存器等,等等。

编辑,作为事后的想法: 我也没有看到有两个代码路径的好处:

25 * sizeof(int)

这会增加相当多的额外开销,而且在嵌入式/移动系统中,更多代码通常不是一个好的计划。

Edit2:另外,如果分配内存是运行时的主要部分,也许看看为什么会这样,例如对象的块创建会有帮助吗?

答案 3 :(得分:2)

为了扩展已经给出的答案,为什么没有可移植的方法来实现这一点,实际堆栈的整个概念不是标准的一部分。您可以编写一个C或C ++运行时,除了函数调用记录(内部可能是链接列表或其他内容)之外,它不会使用堆栈。

堆栈是特定机器/ OS /编译器的实现细节。因此,任何访问堆栈指标的技术都将特定于机器/ OS /编译器。

虽然不是您特定问题的实际答案(Niels非常清楚),但作为对您的问题域的建议:只需在堆中分配一大块内存。除了方便之外没有理由认为“真正的”堆栈是不同的。高度递归(非尾递归)算法通常需要这样做以确保它们具有几乎无界的“堆栈”。想要确保它们提供运行时错误/异常而不是崩溃主机应用程序的脚本语言也经常这样做。为了提高效率,你可以实现一个“拆分堆栈”(就像std::deque会给你的那样),或者你可以确保预先分配一个足够大的堆栈来满足你的需求。

答案 4 :(得分:1)

在语言中没有标准的方法可以做到这一点。我甚至都不知道能够查询的文档扩展名。

但是有些编译器可以选择设置堆栈大小。并且平台可以指定在启动进程时它做什么,和/或提供设置新线程的堆栈大小的方法,甚至可以操纵现有的线程。

对于小型平台,通常知道整个内存大小,一端有所有数据段,堆的设置大小竞技场(可能是0),其余的是堆栈,从另一端接近。 / p>