使用 Visual Studio 确定堆栈空间 [英] Determining Stack Space with Visual Studio

查看:57
本文介绍了使用 Visual Studio 确定堆栈空间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 Visual Studio 2005 中使用 C 进行编程.我有一个多线程程序,但这在这里并不是特别重要.

我如何确定(大约)我的线程使用了多少堆栈空间?

我计划使用的技术是将堆栈内存设置为某个预定值,比如 0xDEADBEEF,长时间运行程序,暂停程序,并调查堆栈.

如何使用 Visual Studio 读写堆栈内存?

参见,例如,如何确定最大堆栈使用量." 这个问题是关于嵌入式系统的,但在这里我试图在普通 PC 上确定答案.

解决方案

Windows 不会立即提交堆栈内存;相反,它为其保留地址空间,并在访问时逐页提交.阅读此页面了解更多信息.>

因此,堆栈地址空间由三个连续区域组成:

  • 保留但未提交的内存,可用于堆栈增长(但尚未访问);
  • 保护页面,它也从未被访问过,并且在访问时触发堆栈增长;
  • 提交的内存,即线程曾经访问过的堆栈内存.

这允许我们构造一个获取堆栈大小(具有页面大小粒度)的函数:

static size_t GetStackUsage(){MEMORY_BASIC_INFORMATION mbi;VirtualQuery(&mbi, &mbi, sizeof(mbi));//现在 mbi.AllocationBase = 保留的堆栈内存基地址VirtualQuery(mbi.AllocationBase, &mbi, sizeof(mbi));//现在 (mbi.BaseAddress, mbi.RegionSize) 描述堆栈的保留(未提交)部分//跳过它VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi));//现在 (mbi.BaseAddress, mbi.RegionSize) 描述保护页//跳过它VirtualQuery((char*)mbi.BaseAddress + mbi.RegionSize, &mbi, sizeof(mbi));//现在 (mbi.BaseAddress, mbi.RegionSize) 描述堆栈的已提交(即访问)部分返回 mbi.RegionSize;}

需要考虑的一件事:CreateThread 允许指定初始堆栈提交大小(通过 dwStackSize 参数,当 STACK_SIZE_PARAM_IS_A_RESERVATION 标志未设置时).如果此参数不为零,则只有当堆栈使用量大于 dwStackSize 值时,我们的函数才会返回正确的值.

I'm programming in C in Visual Studio 2005. I have a multi-threaded program, but that's not especially important here.

How can I determine (approximately) how much stack space my threads use?

The technique I was planning to use is setting the stack memory to some predetermined value, say 0xDEADBEEF, running the program for a long time, pausing the program, and investigating the stack.

How do I read and write stack memory with Visual Studio?

EDIT: See, for example, "How to determine maximum stack usage." That question talks about an embedded system, but here I'm trying to determine the answer on a regular PC.

解决方案

Windows does not commit the stack memory immediately; instead, it reserves the address space for it, and commits it page-by-page when it is accessed. Read this page for more info.

As a result, stack address space consists of three contiguous regions:

  • Reserved but uncommitted memory which can be used for stack growth (but was never accessed yet);
  • Guard page, which was never accessed yet too, and serves to trigger stack growth when accessed;
  • Committed memory, i.e. stack memory which was ever accessed by the thread.

This allows us to construct a function that obtains stack size (with page size granularity):

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;
}

One thing to consider: CreateThread allows to specify initial stack commit size (via dwStackSize parameter, when STACK_SIZE_PARAM_IS_A_RESERVATION flag is not set). If this parameter is nonzero, our function will return correct value only when stack usage becomes greater than dwStackSize value.

这篇关于使用 Visual Studio 确定堆栈空间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆