JXG*_*JXG 7 c memory stack memory-management visual-studio
我在Visual Studio 2005中用C编程.我有一个多线程程序,但这在这里并不是特别重要.
如何确定(大约)我的线程使用多少堆栈空间?
我计划使用的技术是将堆栈内存设置为某个预定值,比如0xDEADBEEF,运行程序很长时间,暂停程序,并调查堆栈.
如何使用Visual Studio读取和写入堆栈内存?
编辑:例如,参见"如何确定最大堆栈使用量". 那个问题谈到了一个嵌入式系统,但在这里我试图在常规PC上确定答案.
atz*_*tzz 15
Windows不会立即提交堆栈内存; 相反,它为它保留地址空间,并在访问时逐页提交.阅读此页面了解更多信息.
因此,堆栈地址空间由三个连续区域组成:
这允许我们构造一个获取堆栈大小的函数(具有页面大小粒度):
static size_t GetStackUsage()
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(&mbi, &mbi, sizeof(mbi));
// now mbi.AllocationBase = reserved stack memory base address
VirtualQuery(mbi.AllocationBase, &mbi, sizeof(mbi));
// now (mbi.BaseAddress, mbi.RegionSize) describe reserved (uncommitted) portion of the stack
// skip it
VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi));
// now (mbi.BaseAddress, mbi.RegionSize) describe the guard page
// skip it
VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi));
// now (mbi.BaseAddress, mbi.RegionSize) describe the committed (i.e. accessed) portion of the stack
return mbi.RegionSize;
}
Run Code Online (Sandbox Code Playgroud)
需要考虑的一件事:CreateThread允许指定初始堆栈提交大小(通过dwStackSize参数,STACK_SIZE_PARAM_IS_A_RESERVATION未设置标志时).如果此参数非零,则仅当堆栈使用量大于dwStackSize值时,我们的函数才会返回正确的值.
您可以使用Win32线程信息块中的信息
当你想在一个线程中找出它使用多少堆栈空间时,你可以这样做:
#include <windows.h>
#include <winnt.h>
#include <intrin.h>
inline NT_TIB* getTib()
{
return (NT_TIB*)__readfsdword( 0x18 );
}
inline size_t get_allocated_stack_size()
{
return (size_t)getTib()->StackBase - (size_t)getTib()->StackLimit;
}
void somewhere_in_your_thread()
{
// ...
size_t sp_value = 0;
_asm { mov [sp_value], esp }
size_t used_stack_size = (size_t)getTib()->StackBase - sp_value;
printf("Number of bytes on stack used by this thread: %u\n",
used_stack_size);
printf("Number of allocated bytes on stack for this thread : %u\n",
get_allocated_stack_size());
// ...
}
Run Code Online (Sandbox Code Playgroud)
堆栈也没有按照您期望的方式工作。堆栈是页面的线性序列,其中最后一个(顶部)用页面保护位标记。当该页被触摸时,保护位被移除,并且该页可以被使用。为了进一步增长,分配一个新的保护页。
因此,您想要的答案是 gaud 页的分配位置。但是您提出的技术会触及有问题的页面,因此它会使您尝试测量的东西无效。
确定(堆栈)页是否具有保护位的非侵入性方法是 via VirtualQuery()。