如何检测我的程序可用的堆栈空间量?

时间:2009-08-28 07:06:36

标签: c++ windows winapi visual-c++

我的Win32 C ++应用程序充当RPC服务器 - 它有一组用于处理请求的函数,RPC运行时创建一个单独的线程并调用该线程中的一个函数。

在我的函数中,我有一个std :: auto_ptr,它用于控制在编译时已知的堆分配的char []数组。它accidentially works when compiled with VC++但根据C ++标准,它是未定义的行为,我想摆脱它。

我有两个选项:std :: vector或堆栈分配的数组。由于我不知道为什么有堆分配的数组,我想考虑用堆栈分配的数组替换它。这个数组是10k个元素,如果RPC运行时生成一个堆栈非常小的线程,我可以假设它会面临堆栈溢出。

我想检测一下典型地为线程分配了多少堆栈空间,以及我的函数有多少可用(它的被调用者肯定消耗了一些分配的空间)。我怎么能这样做?

5 个答案:

答案 0 :(得分:9)

如果您无法访问CreateThread调用,或者如果它是主线程,则查看EXE的默认线程,我不知道如何直接使用API​​计算堆栈大小PE标题中的大小。

在你的情况下,我会在堆上分配是安全的,即使10K的小数据数组不可能在非递归场景中最大化堆栈。

但是,如果仔细进行,您可以探测堆栈限制。当您触摸它们时(通过保护页面),堆栈将在4K页面中提交,直到达到限制为止,Windows将引发堆栈溢出异常。调度异常时仍然有一页堆栈,因此异常调度逻辑本身(包括过滤器函数)可以执行 - 但Windows抛出异常因为它无法分配另一个防护页 。这意味着下一个堆栈溢出或探测不会导致堆栈溢出异常,但会导致访问冲突。因此,为了使探测工作可靠(特别是可重复),您需要解除探测分配的内存并恢复保护页面。

This article on KB describes how to decommit stack memory and reinstate the guard page.它使用递归和10,000字节增量进行探测;默认情况下,编译器实现自己的堆栈探测,查找本地的堆栈分配> 4KB,以便堆栈增长机制正常工作。

答案 1 :(得分:3)

在Windows中,默认堆栈大小为1MB,因此您不可能仅使用10k阵列堆栈溢出。也就是说,我认为在堆栈上分配如此多的内存是一种不好的做法,如果可以的话,你应该尝试动态分配它。还有Scoped Array定义为自动管理数组 - 与vector类不同,它是不可复制的。

答案 2 :(得分:1)

我第二次1800信息:

  • 如果可以,请在堆上分配数据。它更安全(例如缓冲区溢出更难以利用),并且在以后需要扩展设计时(而不是如果)更灵活。

  • 使用std :: vector,boost :: scoped_array或boost :: shared_array。

我知道它没有回答你关于检测堆栈大小的问题,但我认为这是你问题的合理答案。

答案 3 :(得分:0)

我不确定你在追求什么。

如果您只想要典型的数字,请继续尝试!使用嵌套作用域创建一个函数,每个作用域分配更多的堆栈空间。每个范围的输出。看看事情有多远。

如果你想在具体情况下找到具体数字,问问自己一旦拥有它们你想做什么?分成不同的实现?这听起来像是一个维护问题,使用它应该是非常合理的。你期望获得什么?这真的值得这么麻烦吗?

我同意10k通常不应该是个问题。因此,如果您的代码不是关键任务,请继续使用boost::array(或std::tr1::array,如果您的std lib附带它)。否则只需使用std::vector,或者,如果您认为必须,boost::scoped_array(或std::tr1::scoped_array,如果您的std lib附带它)。

答案 4 :(得分:-2)

  

“std :: auto_ptr用于   控制堆分配的char [] ...   这是未定义的行为   C ++“

这是错误的假设! STL的auto_ptr具有精确的行为描述。如果您担心在复杂的任务审核期间失去控制,可以使用引用计数器模式来控制销毁堆分配的数组。