堆栈分配失败而堆分配成功!!这可能吗?

5

我有以下代码片段:

Class Sample
{ Obj_Class1 o1;
  Obj_Class2 o2;};

但是Obj_Class1Obj_Class2的大小非常大,因此编译器会显示警告“考虑将一些空间移动到堆中”。我被要求用Obj_Class1* o1 = new Obj_Class1(); 替换 Obj_Class1 o1。但我认为这种更改没有用处,因为如果堆栈分配失败,堆分配也会失败。我正确吗?或者进行此更改是否有意义(除了抑制编译器警告)。


只是出于好奇,类的大小是多少? - Naveen
另外,您是否能够将Obj_Class1实例替换为指针,而是改变其实现以在堆上分配其需求?即使将其更改为Pimpl也可以帮助解决这个问题。 - Mark B
4个回答

5

栈比堆小是非常典型的情况,它们使用不同的内存位置。栈通常大小约为1MB(您可以更改它,但要小心),并且为每个线程分配。堆可在需要时消耗几GB。


但是堆栈和堆是相互增长的,不是吗? - Prabhu
@Prabhu:是的,但最大堆栈大小仍然受到类似1兆字节的限制。 - sharptooth
@Prabhu:不,它们并不是这样。这是计算机科学课程的一个很好的解释模型,但实际上并没有什么强制要求使用这个模型。 - Billy ONeal

3

栈通常很小,不适合存储大型对象,而堆是单独设计用于存储它们的。

在您的样例中,您应该将整个Sample分配到堆上,而不是其成员:

int main() {
   Sample* sample = new Sample();
}

3

默认情况下,堆栈相对较小:http://msdn.microsoft.com/en-us/library/ms686774(VS.85).aspx

保留和最初分配的堆栈内存的默认大小在可执行文件头中指定。如果没有足够的内存来保留或提交所请求的字节数,则线程或纤程创建将失败。链接器使用的默认堆栈保留大小为1 MB。要为所有线程和纤程指定不同的默认堆栈保留大小,请在模块定义(.def)文件中使用STACKSIZE语句。操作系统将指定的大小舍入到系统分配粒度的最近倍数(通常为64 KB)。要检索当前系统的分配粒度,请使用GetSystemInfo函数。


2

在Visual Studio中,默认情况下,每个线程都会获得1 MB的空间,如果您尝试分配超过这个大小的空间,就会出现堆栈溢出错误。堆没有这个限制,您可以分配的内存量取决于进程虚拟内存中最大的连续空间。因此,如果对象非常巨大,则堆栈分配失败并不奇怪。


吹毛求疵:堆栈溢出并不是在分配超过堆栈大小时发生,而是在分配超过可用堆栈大小时发生。我的意思是,它将会或不会失败取决于已经使用了多少堆栈。 - sharptooth

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