c++ - 测量函数在整个生命周期内在堆和堆栈上分配的总空间

标签 c++ memory-management heap-memory dynamic-memory-allocation stack-memory

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

这是一个如何测量堆栈的示例(这不是我的代码)。

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

编辑
Borgleader 指出我最初的问题“测量最大空间函数在整个生命周期内在堆和堆栈上分配”是不正确的。我已将“最大”更改为“总计”。

最佳答案

Valgrind 实际上可以为你做一个相当精确的测量。您只需要编写尽可能简单的示例来调用您的函数。

例如,一个程序只使用 for 循环和 main() 打印其参数(传递给 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)

正如人们所见,唯一的线程将在堆栈上消耗近 12K。绝对大部分空间都被“浪费了”之前 main() .为了进行更好的测量,有必要在单独的线程中运行目标函数。像这样:
#include <iostream>
#include <thread>

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

此代码将产生以下输出:
==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.

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

您可以使用以下简单算法自己完成几乎相同的操作:
  • 从堆中分配 8M 缓冲区(linux/pthreads 的默认堆栈大小,但您实际上可以分配任何其他(合理)大小)
  • 用一些图案填充它
  • fork 一个新线程,堆栈分配给刚刚分配和填充的区域(使用 pthread_attr_setstack()(或 friend ))
  • 只要您可以在该线程中调用目标函数并退出
  • 在主线程中,在 pthread_join() 之后成功,分析你的缓冲区找到一个区域,你之前分配的模式没有保留

  • (甚至)在这种情况下,您最好对什么都不做的线程进行第一次测量——只是为了获得上述的最小使用大小。

    关于c++ - 测量函数在整个生命周期内在堆和堆栈上分配的总空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13667187/

    相关文章:

    c++ - 如何在 C++ 中有效地实现异构不可变对象(immutable对象)的不可变图?

    c++ - 有没有办法用 googletest 创建自定义参数生成器?

    ios - 文字语法的内存管理

    c++ - 汽车和引用

    c++ - 使用自己的模板所有者 ptr 类分配多维数组

    c++ - 通过 void 指针将对象传递给函数

    debugging - 在 GDB 中,如何找出谁在堆上分配了地址?

    java - 字符串实习如何在 Java 7+ 中工作?

    c++ - 带 d 指针的模板返回

    c++ - 多拷贝构造函数继承中的惊人行为