函数的堆栈分配

4

在以下的32位构建中,有没有针对模块/源文件中内存分配的功能的定量测试:

#include <windows.h>

int main()
{
wchar_t TestArray [516332]  = { NULL };
}

对于516332(或7E0EC),它是成功的,但对于516333却会导致堆栈溢出。 当然,全局声明2Gb或7FFFFFFF是合法的,但再加上一个就会导致堆栈溢出。

#include <windows.h>
wchar_t TestArray [2147483647]  = { NULL };
int main()
{
}

在32位构建中使用VS10/MCBS,但X64不能很好地兼容。在64位或128位系统中,函数类型(例如long、char void、bool)是否有相应的增加?具体寻求采用数值/表格方法的答案。

2个回答

1
短答案是“不行”。没有办法“检查”可用的堆栈空间或堆栈的大小。一些运行时系统具有堆栈空间的知识,但没有标准,从技术上讲,C++标准(或C标准)甚至没有规定应该有这样的堆栈(尽管构建一个没有某种堆栈的系统可能会相当困难,但从技术上讲,它不必是堆栈指针的硬件寄存器,而参数传递可以通过其他机制完成)。
在64位系统中具有更大的堆栈是从技术上讲可能的——我不认为有人已经开始考虑真正的128位系统——我们还有很长的路要走,直到当前系统使用完64位中可用的位数——当前内存映射仅处理53位——要获得更多,需要对页表处理进行更改。目前的处理器 tend to have 48 bits of memory address actually implemented - that still gives 65536 * 4GB, or 256TB. 当前系统最大只有1-2TB,我们还有很长的路要走,才会耗尽当前可用的资源。
尽管在32位环境中技术上可以更大,但堆栈大小通常限制在几兆字节。对于大量数据,您需要使用堆,它的限制要少得多 - 如果您用尽了堆空间,也可以进行恢复,而这通常不是从用尽堆栈空间中恢复的情况 [在函数中使用大量堆栈通常是不好的,因为该函数的其他“使用者”可能不知道它使用了多少内存]。对于小变量,最多几百字节,从堆中分配的开销会很明显,但对于非常大的对象,例如几十万个,在堆上分配它的开销是微不足道的,所以那将是“正确”的做法。
对于类似字符串的东西,我建议:
std::wstring TestString(size);

假设您有所需的大小-它将允许您在该大小处分配单个字符串,而最大大小受可用内存和最大分配大小(这取决于系统,但应至少为2GB左右)的组合限制。

有趣。因此,7E0EC的值可能因不同的安装而异?在问题上稍微“作弊”了一点。这可能是我自己可以做的事情:7E0EC的值是否会根据函数类型而变化? - Laurie Stearn
1
调用“你”的函数之前会起作用 - 所以如果你有一个使用int arr [1000]的函数,那么你的0x7E0EC将减小约 0x1000。我不确定函数的类型是什么 - 是的,从函数返回不同的类型 - struct {int a [500]; } func(...)将比int func(...)使用更多。“安装”并不重要,但C和C ++运行时,编译器和操作系统都将影响堆栈的实际大小,缺省大小(通常也是最大大小)。换句话说,Windows与Linux不同,但两个类似的Linux变体将相同。 - Mats Petersson
如果这是基于某种公式的,是否有可能找到相关文档? - Laurie Stearn
1
没有严格的公式。对于给定的平台,默认的堆栈大小为X。对于给定的函数F1..Fn,堆栈使用量为Y1..Yn。当前调用中所有Y1..Yn的总和是您使用的堆栈量。目标应始终是不要用完堆栈。 - Mats Petersson

1
不确定我是否理解了你的问题,但是:

int main()
{
    wchar_t TestArray [516332]  = { NULL };
}

在这里,您已经触及了默认的1MB线程堆栈大小的限制(一些其他数据也将存在于堆栈上)。可以使用Visual Studio中的/STACK:reserve [,commit]来调整默认大小。

wchar_t TestArray [2147483647]  = { NULL };
int main()
{
}

在32位系统上,您达到了2GB用户模式限制(可以使用/3GB启动开关进行更改)。


谢谢。我不知道/STACK:reserve[,commit]。无论函数的类型如何,这是否都是相同的(稍微修改了一下问题)? - Laurie Stearn
@LaurieStearn - 栈的大小以字节为单位测量,因此它取决于您在其中放置的数据类型。我不确定您所说的函数类型是什么意思,但参数也会被推送到栈上(除非它们直接存储在寄存器中),连同本地变量(也可以是数组)。对于从主线程启动的单独线程,可以为其提供堆栈大小参数。 - Danny_ds

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接