【问题标题】:faster than Stackwalk比 Stackwalk 快
【发布时间】:2026-02-05 14:25:01
【问题描述】:

有没有人知道比“StackWalk”更好/更快的方法来获取调用堆栈? 我也认为stackwalk在有很多变量的方法上也会变慢...... (我想知道商业分析器是做什么的?) 我在 Windows 上使用 C++。 :) 谢谢:)

【问题讨论】:

  • 瓦尔格林德? *.com/questions/413477/…
  • hmmm... valgrind 不只适用于 unix 吗?
  • 并且 valgrind 正在检测,我正在寻找一种更好的方法来对堆栈进行采样...
  • 为什么 StackWalk 对您来说不够快?你需要它做什么?
  • 我遇到了同样的问题。我写了一个泄漏跟踪智能指针,它依赖于StackWalk,但它非常很慢。像 Process Monitor 这样的应用程序是如何做到的(因为 PM 会非常快地记录每个文件/注册表访问的堆栈)?

标签: c++ windows callstack


【解决方案1】:

我使用 Jochen Kalmbachs StackWalker

speedet it up这样:

  • 在默认目录和 PDB 服务器中查找 PDB files 所浪费的时间最多。

  • 我只使用one PDB path 并为我想要解析的图像实现了white list(我不需要寻找user32.pdb)

  • 有时我不需要潜入海底,所以我定义了一个max deep

代码更改:

BOOL StackWalker::LoadModules()
{

    ...

    // comment this line out and replace to your pdb path
    // BOOL bRet = this->m_sw->Init(szSymPath);
    BOOL bRet = this->m_sw->Init(<my pdb path>);

    ...

}

BOOL StackWalker::ShowCallstack(int iMaxDeep /* new parameter */ ... )
{

    ... 

// define a maximal deep
// for (frameNum = 0; ; ++frameNum )
    for (frameNum = 0; frameNum < iMaxDeep; ++frameNum )
    {

        ... 

    }
}

【讨论】:

    【解决方案2】:

    我不知道它是否更快,它不会显示任何符号,我相信你可以做得更好,但这是我不久前在需要此信息时编写的一些代码(仅适用于 Windows):

    struct CallStackItem
    {
        void* pc;
        CallStackItem* next;
    
        CallStackItem()
        {
            pc = NULL;
            next = NULL;
        }
    };
    
    typedef void* CallStackHandle;
    
    CallStackHandle CreateCurrentCallStack(int nLevels)
    {
        void** ppCurrent = NULL;
    
        // Get the current saved stack pointer (saved by the compiler on the function prefix).
        __asm { mov ppCurrent, ebp };
    
        // Don't limit if nLevels is not positive
        if (nLevels <= 0)
            nLevels = 1000000;
    
        // ebp points to the old call stack, where the first two items look like this:
        // ebp -> [0] Previous ebp
        //        [1] previous program counter
        CallStackItem* pResult = new CallStackItem;
        CallStackItem* pCurItem = pResult;
        int nCurLevel = 0;
    
        // We need to read two pointers from the stack
        int nRequiredMemorySize = sizeof(void*) * 2;
        while (nCurLevel < nLevels && ppCurrent && !IsBadReadPtr(ppCurrent, nRequiredMemorySize))
        {
            // Keep the previous program counter (where the function will return to)
            pCurItem->pc = ppCurrent[1];
            pCurItem->next = new CallStackItem;
    
            // Go the the previously kept ebp
            ppCurrent = (void**)*ppCurrent;
            pCurItem = pCurItem->next;
            ++nCurLevel;
        }
    
        return pResult;
    }
    
    void PrintCallStack(CallStackHandle hCallStack)
    {
        CallStackItem* pCurItem = (CallStackItem*)hCallStack;
        printf("----- Call stack start -----\n");
        while (pCurItem)
        {
            printf("0x%08x\n", pCurItem->pc);
            pCurItem = pCurItem->next;
        }
        printf("-----  Call stack end  -----\n");
    }
    
    void ReleaseCallStack(CallStackHandle hCallStack)
    {
        CallStackItem* pCurItem = (CallStackItem*)hCallStack;
        CallStackItem* pPrevItem;
        while (pCurItem)
        {
            pPrevItem = pCurItem;
            pCurItem = pCurItem->next;
            delete pPrevItem;
        }
    }
    

    【讨论】:

      【解决方案3】:

      查看http://msdn.microsoft.com/en-us/library/bb204633%28VS.85%29.aspx - 这是“CaptureStackBackTrace”,虽然它被称为“RtlCaptureStackBackTrace”。

      【讨论】: