在C++中,线程中的堆栈大小是什么意思?

9
我正在使用C++和Windows.h源代码。我在MSDN中阅读了CreateThread API,但仍然不理解指定堆栈大小的实质。默认情况下是1 MB。但如果我指定32字节会发生什么?
线程中的堆栈大小是什么意思?
请提供详细的解释,谢谢。

3
您提供的页面包含以下内容:*更多信息请参见线程堆栈大小*。请阅读您自己链接到的文档。 - bolov
可能要求一个32字节的堆栈甚至不可能,最小大小应该是一个内存页(通常为4 KB)。 - Matteo Italia
1
与您的问题无关,但在使用C++时,您应该调用_beginthreadex而不是CreateThread。这在文档中明确说明了。 - IInspectable
有一种非常简单的方法可以找出发生了什么。试试看。 - Hans Passant
@HarryJohnston:你提到的是一个已经不存在的问题,即在调用CreateThread创建使用CRT的线程时存在内存泄漏。据我所知,文档中记录的问题(“如果使用CreateThread创建的线程调用CRT,则CRT可能会在低内存条件下终止进程。”)仍然存在。无论如何,调用_beginthreadex始终是安全的,并且不会施加任何限制。 - IInspectable
显示剩余2条评论
3个回答

25

堆栈用于存储局部变量、在函数调用时传递参数、存储返回地址。线程的堆栈具有固定大小,这个大小在创建线程时确定。这就是你正在引用的值。

堆栈大小在创建线程时确定,因为它需要占用连续的地址空间。这意味着线程堆栈的整个地址空间必须在创建线程时被保留。

如果堆栈太小,它就可能溢出。这是一个称为 "堆栈溢出 "的错误条件,这个网站就是从这个错误条件中取名的。在调用函数时,可能会发生以下一些或所有的情况:

  • 将参数推入堆栈。
  • 将返回地址推入堆栈。
  • 创建一个包含函数局部变量空间的堆栈帧。

所有这些都会消耗堆栈的空间。当函数依次调用另一个函数时,会消耗更多的堆栈空间。随着调用堆栈深度的增加,需要更多的堆栈空间。

因此,将堆栈大小设置得太低的后果是,您可能会耗尽堆栈并导致其溢出。这是一个无法恢复的终端条件。对于几乎所有线程来说,32字节(向上舍入为4096字节)的大小都太小了。

如果您有一个具有大量线程的程序,并且知道线程不需要保留1MB的堆栈大小,则使用较小的堆栈大小可能会带来好处。这样做可以避免耗尽可用的进程地址空间。

另一方面,您可能有一个具有深度调用堆栈的单个线程的程序,该堆栈消耗大量堆栈空间。在这种情况下,您可能会保留超过默认值1MB的大小。

但是,除非您有足够的理由进行更改,否则最好坚持使用默认堆栈大小。


也许这只是我的想法,但在第二段中,你好像在说必须保留整个进程地址空间,或许你应该重新措辞。此外,增加一些情况的例子会更有趣,例如何时可能希望设置较低或较高的线程堆栈大小。 - Matteo Italia
点赞,我认为这是一个可以的答案。第二段看起来不错。额外提供的信息可能会让人更加困惑,而不是更加清晰地说明未来的实现。 - Cheers and hth. - Alf

1

堆栈大小只是创建多个线程的能力和其中一个线程发生堆栈溢出的可能性之间的权衡。

堆栈大小越大,可以创建的线程数量就越少,堆栈溢出的可能性也越小。只有当您打算创建许多线程时,才应该担心堆栈大小(您将不得不降低堆栈大小,但要记住堆栈溢出)。否则,默认值就足够了。


0
“但如果我指定32字节会发生什么?”
我没有阅读Windows文档,但是如果Windows允许这样做(只指定32字节),则最有可能会出现堆栈溢出。根据他们的文档,该值将在任何情况下舍入至页面大小,因此实际上您的堆栈大小至少为一个页面大小。创建的线程假定存在足够的“堆栈空间”供其使用(用于分配自动变量、存储函数地址等),并根据其需要分配空间。当没有足够的堆栈空间时,堆栈分配器可能会使用无效内存,覆盖其他地方使用的内存。
“线程中的堆栈大小定义是什么?”
它定义了为该线程的堆栈分配多少内存可以使用。
关于什么是线程调用堆栈的详细描述,请参见here

给那些给我打分的人,请您好心给出一个充分的理由。要理解“size”所指的内容,首先需要了解“stack”的概念。从这里可以清楚地看出“size”所指的是什么,不是吗?还有比这更好的关于“stack”定义的解释吗? - Werner Erasmus

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