【问题标题】:Stack Allocation For Functions函数的堆栈分配
【发布时间】:2016-04-14 05:47:40
【问题描述】:

模块/源文件中的函数是否有任何关于内存分配的量化测试,如以下 32 位构建所示:

#include <windows.h>

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

对于 516332(或 7E0EC)会成功,但会为 516333 产生堆栈溢出。 当然,2Gb 或 7FFFFFFF 的全局 decl 是合法的,但添加一个即可获得 SO。

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

在 32 位版本中使用 VS10/MCBS,但 X64 性能不佳。在 64 或 128 系统中,函数类型(例如 long、char void、bool)是否有成比例的增加?专门用数字/表格方法寻找答案。

【问题讨论】:

    标签: c++ memory stack overflow allocation


    【解决方案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]。无论函数的 type 是什么,都一样吗(稍微修改了问题)?
    • @LaurieSearn - 堆栈以字节为单位,因此取决于您放入的数据类型。我不确定您对函数类型的含义,但参数也被推送到堆栈上(除非它们直接存储在寄存器中) - 以及局部变量(也可以是数组)。对于从主线程开始的单独线程,可以为堆栈大小提供一个参数。
    【解决方案2】:

    简短的回答是“不”。没有办法“检查”有多少可用的堆栈空间,或者堆栈有多大。一些运行时系统具有堆栈空间的知识,但没有标准,从技术上讲,C++ 标准(或 C 标准)甚至没有规定应该有这样的堆栈(尽管这会相当困难构建一个没有某种堆栈的系统,但从技术上讲,它不必是堆栈指针的硬件寄存器,参数传递可以完全通过某种其他机制完成)。

    在 64 位系统中拥有更大的堆栈在技术上是可能的 - 我认为还没有人开始考虑真正的 128 位系统 - 在当前系统用完可用的系统之前,我们有一个公平的方法64 位中的位 - 当前内存映射仅处理 53 位 - 要获得更多,需要在页表处理中进行更改。而当前的处理器往往实际实现了 48 位内存地址 - 仍然提供 65536 * 4GB 或 256TB。当前系统的最大容量为 1-2TB,在我们用完当前可用的容量之前,我们还有相当长的路要走。

    尽管在技术上可能更大,即使在 32 位环境中,堆栈大小通常也限制在几兆字节。对于大量数据,你想使用堆,它的限制要小得多——如果你用完了,有可能恢复,这通常不是用完堆栈空间 [和使用大量函数中的堆栈通常很糟糕,因为该函数的其他“消费者”可能没有意识到它使用了多少内存]。对于小变量,最多几百字节,从堆分配的开销会很明显,但是对于非常大的对象,比如几十万个wchar_t,在堆上分配的开销是微不足道的,所以将是“正确”的事情。

    对于类似字符串的东西,我建议:

    std::wstring TestString(size);
    

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

    【讨论】:

    • 有趣。那么 7E0EC 的值会因不同的安装而异吗?通过在问题中添加更多内容来“欺骗”。这可能是我自己可以做的事情:7E0EC 的值会根据函数type而变化吗?
    • 在“你的”函数之前的调用很重要 - 所以如果你有一个使用的函数,比如int arr[1000];,那么你的0x7E0EC 将小大约0x1000。我不确定函数的 type 是什么 - 是的,与函数不同的返回类型 - struct { int a[500]; } func(...) 将使用更多 int func(...) “安装”并不重要,但是 C 和 C++ 运行时、编译器和操作系统都会影响堆栈的实际和默认(通常是最大)大小。换句话说,Windows 将不同于 Linux,但 Linux 的两个相似变体将是相同的。
    • 如果这是基于某种公式,是否可以找到它的文档?
    • 没有严格的公式。对于给定平台,默认堆栈大小为 X。对于给定函数 F1..Fn,堆栈使用量为 Y1..Yn。当前调用中所有活动的 Y1..Yn 的总和是您使用的堆栈数。目标应该始终是不耗尽堆栈。
    猜你喜欢
    • 1970-01-01
    • 2012-06-26
    • 2011-10-06
    • 2018-06-18
    • 2012-01-28
    • 2012-08-01
    • 2019-09-16
    • 2013-10-29
    • 2017-08-12
    相关资源
    最近更新 更多