C++ 对于应该使用多大的对象堆来代替堆栈?

C++ 对于应该使用多大的对象堆来代替堆栈?,c++,stack-overflow,C++,Stack Overflow,我想知道有多大的物体对堆栈来说太大了?如果我们谈论的是普通PC(Windows或Linux)。我试图找到答案,但我所发现的只是,若对象太大,那个么在堆上进行分配。但是什么东西太大了?几KB?或者几百KB?我知道这通常不是一个问题,但它困扰着我,因为我不知道答案 一些代码: int main() { int a[1000][300]; /* enough for stack overflow :) on Visual Studio 2012 without any specific set

我想知道有多大的物体对堆栈来说太大了?如果我们谈论的是普通PC(Windows或Linux)。我试图找到答案,但我所发现的只是,若对象太大,那个么在堆上进行分配。但是什么东西太大了?几KB?或者几百KB?我知道这通常不是一个问题,但它困扰着我,因为我不知道答案

一些代码:

int main()
{
    int a[1000][300]; /* enough for stack overflow :) on Visual Studio 2012 without any specific setting. int a[1000][250] is Ok */
    return 0; 
}
还有:

int main()
{
    MySmallClass a; // I want to use RAII
    MyBigClass b; // ouch I shouldn't do it
    unique_ptr<MyBigClass> c(new MyBigClass()) // So I would do something like this to keep RAII
    return 0; 
}
intmain()
{
MySmallClass a;//我想使用RAII
MyBigClass b;//哎哟,我不该这么做
unique_ptr c(new MyBigClass())//所以我会这样做来保持RAII
返回0;
}
由于VisualStudio似乎在仅1MB的堆栈分配方面存在问题,因此在最大大小为几KB的堆栈对象上进行分配似乎是合理的,因为堆栈可以非常深入。这并不多,对于第三方对象,我甚至不知道(因为我根本不想知道)它们有多大,我只能期望它们会合理地小


实际上,当我制作大型静态数组来测试某些性能时,我只遇到过一次这种问题。因此,在现实生活中,这可能不是常见的问题,但仍然…

这个问题没有简单的答案

一个物体? 一些运行时确定的数量?
对象是在每次循环或递归调用时创建的吗

因为堆栈溢出很难识别,所以所有这些选择都会影响您在选择将大对象放入堆栈时的谨慎程度


在我所研究的嵌入式系统中,很少讨论堆栈与堆。相反,问题只是“对象的生命周期是什么”

而且,也许令人惊讶的是,大多数“重要”对象都是在启动时创建的,从未被破坏过。i、 e.它们一直持续到系统复位或断电

在这个嵌入式环境中,重要的对象都在堆中


当然,在一个实体系统中,也有许多对象只持续到函数(或方法)的末尾

这些短期对象要么适合(要么不适合)与使用它们的单个线程相关联的堆栈。在该版本的vxWorks中没有运行时堆栈大小更改机制(我知道)。每个任务(我认为对应于linux线程)都有一个在编译时确定的堆栈大小。有时,我们确实把这堆东西弄得满满的

当您发现并确信程序中存在堆栈溢出时,有两种解决方案(或者更多)

  • 在一个特定的案例中,我的团队决定扩展特定的线程堆栈大小。溢出是该线程独有的

  • 在其他几个例子中,我们在函数开始时将对象添加到堆中,并在退出时将其删除。很简单,对吧

这是唯一的两个选择吗?也许吧

所以,如果你必须要有一个数字,我会说寻找别人的经验法则


作为一名经验丰富的嵌入式系统开发人员,我的选择如下:

  • 我将非平凡对象保留在堆上

  • 堆栈上的少量相对简单的对象

  • 生命周期问题只能将事物从堆栈推到堆中

  • 较大的大小只能将内容从堆栈推送到堆中

就个人而言,我对使用new和delete非常满意,并且对所有权问题有自己的看法。然而。。。我的“风格”选择并不适合所有人。而且有很多文献表明,最终,复杂性会混淆关于什么任务拥有什么对象(以及哪个任务应该删除哪些对象)的任何知识

现在,弄清楚你所说的“非琐碎”和“简单”是什么意思


关于std::vector、std::strings、std::stringstream和map,它们都是相对复杂的对象(IMHO)

但是,如果使用sizeof(),则即使在填充时,它们也非常小。我认为这意味着它们都是堆访问的“前端”

另一方面,它们的性能很好,可能正在做其他事情(与堆无关),但我还没有研究过


要了解更多信息。

不是Visual Studio,而是Windows为您提供了1MB默认堆栈大小。如果你控制线程的创建,你可以要求更多。
这并不多,而且对于第三方对象,我甚至不知道(因为我根本不想知道)它们有多大。
任何第三方库给你的对象很容易被堆栈吹走,这在我看来都是一个低质量的库。这为什么如此重要?只要选择一个任意的限制,然后继续做有用的工作。如果您不能自行选择,那么完美的限制显然是65536字节。您可以在编译程序时或在程序本身内指定总堆栈容量,具体取决于编译器和操作系统。默认情况下,它介于1MB和8MB之间。但是,当然,你为每个函数(它的局部变量)设置的实际限制应该至少低一千倍,IMHO。所以,几KB是一个很好的大概数字。只要避免大型静态数组,大体上,我会说大约超过100个元素。不管怎样,在数据量如此之大的情况下,避免堆对性能没有多大好处。