是否有一种方法可以测量特定函数从堆栈中消耗了多少内存?
Is there a way to measure how much memory a specific function consumes from stack?
是否有一种方法可以测量一个特定的c++函数从被调用到返回时从程序堆栈中消耗了多少内存?
假设有一个函数"testfunc",我们希望找到这个函数使用了多少堆栈空间.....
#include <stdio.h>
#include <stddef.h>
ptrdiff_t testfunc (int arg1, int arg2, char *stackbase);
int main()
{
char *stackbase;
printf("nThe amount of stack space used by "testfunc" is : %ul bytesn",testfunc(10, 5, stackbase));
return 0;
}
ptrdiff_t testfunc (int arg1, int arg2, char *stackbase)
{
//.
//all function processing goes here
//.
//.
char temp;
return stackbase - &temp;
}
http://cboard.cprogramming.com/c-programming/90572-determine-functions-stack-size.html
显然没有可移植的方法,因为编译器被允许对函数做很多事情:从内联到尾部调用优化。
但严格来说,没有什么可测量的,因为编译器知道这个数字。好吧,除非你使用非常量大小的堆栈数组(在C99中允许,但在c++中不允许)。
一种愚蠢的方法是查看汇编代码:
例如,这个函数:
int f(int x, int y)
{
int z = x + y;
int h = z - 2;
return h;
}
在amd64上编译为:
f:
.LFB0:
.cfi_startproc
pushq %rbp ; save the pointer to the caller's frame
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp ; new frame starts from %rsp (current stack ptr)
; starting from this place look how %rbp is used
; the maximum offset is what you're looking for
.cfi_def_cfa_register 6
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
movl -20(%rbp), %edx
movl -24(%rbp), %eax
addl %edx, %eax
movl %eax, -8(%rbp)
movl -8(%rbp), %eax
subl $2, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
所以,在这个例子中,函数f将8字节的%rbp(旧帧指针)压入堆栈,然后它使用%rbp-20, %rbp-24, %rbp-8和%rbp-4的内存。最大偏移量为-24。使用的总字节数是24字节加上%rbp的8字节和这里不可见的返回指针的8字节,如果我没有忘记任何东西,总共40字节。
我不确定这是不是你问的。
首先要查看的是该函数的C编译器的汇编输出,并计算所有的调用、推送和堆栈帧。然后你需要对调用树中的所有函数重复,找到最长的路径,并为它求和。
如果可以在调试器中运行该函数,只需在调用该函数之前记录堆栈指针的值,逐步进入该函数,直到到达最深处,并记录堆栈指针的值。这给你一个真实世界的数字。
如果可以重新编译整个函数树,请添加一个简单的序言和尾声宏,用于在全局变量中记录堆栈指针的低水位标记。重新编译整个项目并运行它。这为您提供了许多迭代的真实数字。
如果您的函数调用到您不可见的第三方代码,则问题变得更加棘手。为此,您可以简单地从当前堆栈点以下40(或左右)字节开始memset堆栈内存,调用该函数,然后查找自memset以来未动过的内存。
类似于(未经测试!):
编辑:哎呀,忘了堆栈是向下增长的…
int StackTest() {
//marker is on the stack.
//"volatile" prevents it from optimized into a register.
volatile unsigned int marker= 0xDEADBEEF;
//The current stack pointer should be just below marker.
//I add 10*4 to move well below the current stack frame.
//If the program crashes at this point, try increasing
//the size of the buffer zone.
char *pStack= (char*)&marker[-10];
//I zap the unused stack space to a recognizable value.
//The fill bytes will be overwritten as the stack is used.
//The 4096 number may need to be adjusted; it needs to be
//larger than the stack bytes used but less than the total
//stack space remaining.
memset(pStack-4096,0xCD,4096);
//Now I call my target function.
function();
//Now I search for the first 8 fill bytes in a row.
//This number may need to be increased to rule out
//false positives, such as buffers (arrays) allocated
//on the stack but not completely filled, which leaves
//fill bytes untouched inside the buffer.
for(n1=0,matchCt=0;n1<4096 && matchCt<8;n1++) {
if(*(pStack-n1)==0xCD)
matchCt++;
else
matchCt= 0;
}
int stackUsed= n1-matchCt;
printf("Stack used: %d bytes.n",stackUsed);
return(stackUsed);
}
请记住,硬件中断也可以在随机时间消耗堆栈。编辑:这可能不是用户进程所关心的。
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- "main"函数堆栈中的对象在第一个任务运行时被覆盖 (FreeRTOS)
- 提升堆栈跟踪不显示函数名称和行号
- C++析构函数调用两次,堆栈分配的复合对象
- 静态堆栈函数不会 1) 输入第一个元素 2)添加新元素时识别旧元素
- 以下代码如何工作以每次为唯一调用堆栈唯一实例化模板函数?
- 如何修复递归函数导致的堆栈溢出错误?C++
- 如果类在堆上,函数是转到堆还是堆栈?
- C++ 中的构造函数、继承、堆栈、堆、this-pointer 和段错误
- 何时在函数中声明堆栈分配变量?
- 使用在堆栈上创建的对象调用虚拟函数
- 为什么析构函数无休止地调用自己(导致堆栈溢出)?
- 双链表堆栈删除函数不起作用
- 函数,该函数将在堆栈底部保留最小的出现次数
- 我正在尝试使用递归来反转堆栈.函数 fun() 中传递了什么?s 是类堆栈的对象
- Visual C++ 堆栈函数和错误处理
- 如何知道堆栈函数消耗了多少
- 如何在这个无锁堆栈函数中防止未定义的行为和ABA问题
- 打印堆栈函数
- 堆栈函数应该返回指定的元素,而不是返回垃圾值