代码之家  ›  专栏  ›  技术社区  ›  JXG Jasmynn Flores

用visualstudio确定堆栈空间

  •  7
  • JXG Jasmynn Flores  · 技术社区  · 15 年前

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

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

    如何使用visualstudio读写堆栈内存?

    编辑:例如, "How to determine maximum stack usage." 这个问题讲的是嵌入式系统,但我想在普通PC机上确定答案。

    4 回复  |  直到 7 年前
        1
  •  16
  •   atzz    15 年前

    Windows不会立即提交堆栈内存,而是为其保留地址空间,并在访问时逐页提交。阅读 this page 更多信息。

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

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

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

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

    有一点需要考虑: CreateThread dwStackSize 参数,当 STACK_SIZE_PARAM_IS_A_RESERVATION 未设置标志)。如果这个参数是非零的,我们的函数将返回正确的值只有当堆栈使用变得大于 dwStackSize文件 价值观。

        2
  •  7
  •   user184968 user184968    15 年前

    Win32 Thread Information Block

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

    #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());    
        // ...
    }
    
        3
  •  1
  •   MSalters    15 年前

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

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

    确定(堆栈)页是否具有保护位的非侵入性方法是通过 VirtualQuery() .

        4
  •  -1
  •   denisenkom    15 年前

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