我正在构建一个小型软件引擎,并且我希望大量使用栈来快速迭代大量集合。但是后来我想到这可能是一个坏主意,因为堆栈不像堆一样大。但是我被这个栈的速度所吸引,并且缺乏动态分配编码实践。是否可以确定堆栈上有多少空间可用?
有没有办法找出我可以在特定平台上推送堆栈多远?我主要关注移动设备,但这个问题可能出现在任何平台上。
我正在构建一个小型软件引擎,并且我希望大量使用栈来快速迭代大量集合。但是后来我想到这可能是一个坏主意,因为堆栈不像堆一样大。但是我被这个栈的速度所吸引,并且缺乏动态分配编码实践。是否可以确定堆栈上有多少空间可用?
有没有办法找出我可以在特定平台上推送堆栈多远?我主要关注移动设备,但这个问题可能出现在任何平台上。
在* 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中减去 的大小:这将为您提供为堆栈保留的空间大小 (假设您不是 正好在堆栈的极限上大小在当时)。总结这两个 自然会给你总的堆栈大小。
由于堆栈大小在逻辑上属于实施和主机系统,因此没有独立于平台的方法 - 在嵌入式小型SOC上,分配的资源少于在128GB RAM服务器上分配的资源。但是,您可以通过特定于API的调用来影响所有操作系统上特定线程的堆栈大小。
从语言中没有标准的方法。我甚至没有意识到可以查询的文档扩展名。
但是有些编译器可以选择设置堆栈大小。平台可以指定它在启动进程时的功能,和/或提供设置新线程的堆栈大小的方法,甚至可以操纵现有的线程。
对于小平台,通常知道整个内存大小,一端有所有的数据段,一个是堆大小的舞台(可能是0),其余的是栈,接近另一端。
在标准的C++中,绝对不是。以便携的方式,可能不是。有时候在特定的操作系统中。如果没有别的,你可以打开你自己的可执行文件大小并检查可执行文件的头文件来查看它的大小。 [下一个问题当然是“在这段代码之前使用了多少堆栈” - 这可能很难确定)。
如果您在单独的线程中运行代码,许多(低级别)线程接口允许您指定堆栈(或堆栈大小),例如Posix线程pthread_set_stacksize
或MS _beginthread
。再次,你不知道在达到实际的线程代码之前已经占用了多少空间 - 但它可能不是一个巨大的数量。当然,在嵌入式系统(例如手机)中,堆栈大小通常非常小,4K,12K或64KB非常正常 - 有时甚至比有些系统小得多。
另一个潜在的问题是,你不能真正知道在堆栈中实际使用了多少空间 - 你可以在编译系统中测量这个事实,当然,如果你有一个堆栈本地数组int array[25];
,我们可以知道它占用至少25 * sizeof(int)
- 但有可能是填充,编译器保存在栈上的寄存器,等等,等等
编辑,事后的想法: 我还没有真正看到有那么多好处两个代码路径:
if (enough_stack_space_for_something)
use_stack_based_algorithm();
else
use_heap_based_algorithm();
这会增加相当数量的额外开销和更多的代码在嵌入式/移动系统中通常不是一个好计划。编辑2:另外,如果分配内存是运行时的主要部分,也许看看为什么,例如块的对象创建会有所帮助?
可能的便携式解决方案是自己编写一个分配器。
您不必使用进程堆栈,只需在堆中模拟即可。
在开始时分配大量内存,并在其上写入堆栈分配器以在分配时使用它。
有关如何在C++中实现它的信息,Google的“分配器要求”。
我不确定'Stack Allocator'这个术语是否是规范的,但我的意思是说你必须把堆栈放在像分配或释放的地方那样的限制上。
既然你说你的算法适合这种模式,我认为这很容易。
为了扩大已经给出的答案,为什么没有可移植的方式来做到这一点,实际堆栈的整个概念不是标准的一部分。你可以编写一个C或C++运行时,除了函数调用记录(可能内部是一个链表或其他东西)之外,它不会使用栈。
堆栈是特定机器/操作系统/编译器的实现细节。因此,任何访问堆栈度量的技术都将针对机器/操作系统/编译器。
虽然不是你的具体问题的实际答案(Niels覆盖了这个很好),但作为你的问题领域的建议:只是在堆中分配一大块内存。除了方便之外,没有任何理由说明“真正”的堆栈有什么不同。高度递归(非尾递归)算法经常需要这样做,以确保它们具有几乎无限的“堆栈”。希望确保它们提供运行时错误/异常而不是崩溃主机应用程序的脚本语言也经常这样做。为了有效地处理事情,你可以实现一个“拆分堆栈”(就像std::deque
会给你的),或者你可以确保预先分配一个足够大的栈来满足你的需求。
除了方便以外,没有任何理由可以说“真正”的堆栈有任何不同。但是经常提到堆栈比堆快,所以它肯定不仅仅是方便吗? – johnbakers
堆上的_Allocations_(使用'malloc'或'new'或类似的东西)比在堆栈上创建局部变量或使用类似'alloca'的东西慢。堆栈大多会自动避免碎片和缓存局部性问题,如果您天真但可能会因堆使用而受到影响,但如果您小心,这些问题不会成为问题。一些体系结构具有用于实现堆栈的明确指令,例如, x86上的'push'和'pop',但在大多数算法中它们的优势将极其微小。除非你有性能数字证明你需要,否则不要担心。 –
不是重复的,但看看http://stackoverflow.com/q/1756285/1729885 –
所以你想动态地(即在运行时)确定堆栈大小? – ComFreek
我不认为有任何一般的解决方案。堆栈大小可以在不同的线程之间有所不同 –