visual-studio 使用 Visual Studio 确定堆栈空间

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1740888/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 11:13:33  来源:igfitidea点击:

Determining Stack Space with Visual Studio

cvisual-studiomemorymemory-managementstack

提问by JXG

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

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

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.

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

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

如何使用 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.

编辑:例如,请参阅“如何确定最大堆栈使用量”。这个问题是关于嵌入式系统的,但在这里我试图在普通 PC 上确定答案。

回答by atzz

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 pagefor more info.

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

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: CreateThreadallows to specify initial stack commit size (via dwStackSizeparameter, when STACK_SIZE_PARAM_IS_A_RESERVATIONflag is not set). If this parameter is nonzero, our function will return correct value only when stack usage becomes greater than dwStackSizevalue.

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

回答by JXG

You can make use of information in the Win32 Thread Information Block

您可以利用Win32 线程信息块中的信息

When you want in a thread to find out how much stack space it uses you can do something like this:

当您想在一个线程中找出它使用了多少堆栈空间时,您可以执行以下操作:

#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());    
    // ...
}

回答by MSalters

The stack doesn't work the way you expect it too. The stack is a linear sequence of pages, the last (top) one of which is marked with a page guard bit. When this page is touched, the guard bit is removed, and the page can be used. For further growth, a new guard page is allocated.

堆栈也不会按您期望的方式工作。堆栈是页面的线性序列,其中最后一个(顶部)用页面保护位标记。当该页面被触摸时,保护位被移除,并且该页面可以被使用。为了进一步增长,分配了一个新的保护页。

Hence, the answer you want is where the gaurd page is allocated. But the technique you propose would touch the page in question, and as a result it would invalidate the very thing you're trying to measure.

因此,您想要的答案是 gaurd 页面的分配位置。但是您提出的技术会触及有问题的页面,因此它会使您试图衡量的东西无效。

The non-invasive way to determine if a (stack) page has the guard bit is via VirtualQuery().

确定(堆栈)页面是否具有保护位的非侵入式方法是 via VirtualQuery()

回答by denisenkom

You can use GetThreadContext() function to determine thread's current stack pointer. Then use VirtualQuery() to find stack base for this pointer. Substracting those two pointers will give you stack size for given thread.

您可以使用 GetThreadContext() 函数来确定线程的当前堆栈指针。然后使用 VirtualQuery() 查找此指针的堆栈基数。减去这两个指针将为您提供给定线程的堆栈大小。