测量总空间函数在整个生命周期中分配堆和堆栈

new*_*int 1 c++ heap stack memory-management dynamic-memory-allocation

我有一个用C++编写的递归函数,它使用动态分配2D数组new.我怎样才能测量在整个生命周期内空间函数在堆和堆栈上分配的总量?

以下是如何测量Stack的示例(不是我的代码).

unsigned int maxStackLocation ; 
unsigned int minStackLocation ; 
main () 
{ 
    //get the address of a local variable before calling Quicksort 
    //the stack grows down, so this is the max stack location 
    int localVariable;
    void *currPtrLocation = (void*)(&localVariable); 
    maxStackLocation = *(unsigned int *)(&currPtrLocation); 
    //we get the value for the minimum stack location in quicksort itself 
    //call quicksort 
    Quick (A, num); 
    space = maxStackLocation - minStackLocation;
} 
//some redundant function whose stack usage will be measured
void Quick (unsigned int A[], int num) 
{ 
    if (num <= 1) 
    { 
        //check the stack usage 
        //figure out where we are on the stack by looking at the byte  
        // address of the local variable 
        //we do this by making a pointer to a local variable, and then  
        //casting it to a integer 
        void *currPtrLocation = (void*)(&num); 
        unsigned int currStackLocation = *(unsigned int*)(&currPtrLocation); 
        if (currStackLocation < minStackLocation) 
            minStackLocation = currStackLocation; 
        return; 
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑
Borgleader指出我的原始问题"测量最大空间函数在堆和堆栈的整个生命周期中分配"是不正确的.我已将"max"更改为"total".

zau*_*ufi 7

Valgrind实际上可以为您做一个非常精确的测量.您需要的只是尽可能简单地编写调用函数的示例.

例如,一个程序只main()使用for循环打印其参数(传递给函数)并std::cout产生以下输出:

zaufi@gentop /work/tests $ valgrind --tool=drd --show-stack-usage=yes ./stack-usage-test-1
==26999== drd, a thread error detector
==26999== Copyright (C) 2006-2012, and GNU GPL'd, by Bart Van Assche.
==26999== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==26999== Command: ./stack-usage-test-1
==26999==
./stack-usage-test-1
==26999== thread 1 finished and used 11944 bytes out of 8388608 on its stack. Margin: 8376664 bytes.
==26999==
==26999== For counts of detected and suppressed errors, rerun with: -v
==26999== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Run Code Online (Sandbox Code Playgroud)

可能会看到唯一的线程将在堆栈上消耗近12K.绝对大部分的空间被"浪费" 之前main().要进行更好的测量,必须在单独的线程中运行目标函数.像这样的Smth:

#include <iostream>
#include <thread>

int main(int argc, char* argv[])
{
    auto thr = std::thread([](){std::cout << __PRETTY_FUNCTION__ << std::endl;});
    thr.join();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码将生成以下输出:

==27029== thread 2 finished and used 1840 bytes out of 8384512 on its stack. Margin: 8382672 bytes.
==27029== thread 1 finished and used 11992 bytes out of 8388608 on its stack. Margin: 8376616 bytes.
Run Code Online (Sandbox Code Playgroud)

这肯定更好.因此,测量一个什么都不做的函数,你有一个最小的堆栈使用(在最后一个例子中,它大约是1840字节).因此,如果您在单独的线程中调用目标函数,则必须从结果中减去1840字节(甚至更少)...


您可以使用以下简单算法自己完成相同的操作:

  1. 从堆中分配8M缓冲区(linux/pthreads的默认堆栈大小,但实际上可以分配任何其他(合理的)大小)
  2. 用一些模式填充它
  3. fork一个新线程,堆栈分配给刚分配和填充的区域(使用pthread_attr_setstack()(或朋友))
  4. 只要你可以在该线程中调用目标函数并退出
  5. 在主线程中,在pthread_join()成功之后,分析您的缓冲区以找到您之前分配的模式未保留的区域

(偶数)在这种情况下,你最好在一个什么都不做的线程上进行第一次测量 - 只是为了获得如上所述的最小使用大小.