有没有办法测量特定c ++函数从调用它到返回时从程序堆栈中消耗多少内存?
答案 0 :(得分:0)
假设有一个函数" 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 bytes\n",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
答案 1 :(得分:0)
显然没有可移植的方式,因为允许编译器对函数做很多事情:从内联到尾调用优化。
但严格来说,没有什么可以衡量的,因为编译器完全知道这个数字。好吧,除非您使用非常量大小的堆栈数组(在C99中允许使用,但在C ++中不允许)。
找出一个愚蠢的方法是查看汇编代码:
例如,这个函数:
using System;
using System.Windows.Forms;
namespace TestListBox
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
listBox1.Items.Add(new TestClass("asd"));
listBox1.Items.Add(new TestClass("dsa"));
listBox1.Items.Add(new TestClass("wqe"));
listBox1.Items.Add(new TestClass("ewq"));
}
private void button1_Click(object sender, EventArgs e)
{
((TestClass)listBox1.Items[0]).Name = "123";
listBox1.Refresh(); // doesn't help
listBox1.Update(); // same of course
}
}
public class TestClass
{
public string Name;
public TestClass(string name)
{
this.Name = name;
}
public override string ToString()
{
return this.Name;
}
}
}
在amd64上编译为:
int f(int x, int y)
{
int z = x + y;
int h = z - 2;
return h;
}
因此,在此示例中,函数f将堆栈推送到8字节%rbp(旧帧指针),然后它使用%rbp-20,%rbp-24,%rbp-8和%rbp-4的内存。最大偏移为-24。 使用的字节总数是24个字节加上8个字节用于%rbp和8个字节在这里对于返回指针是不可见的,如果我没有忘记任何事情,总共40个字节。
我不确定这是不是你问过的。
答案 2 :(得分:0)
首先要看的是C编译器对该函数的汇编输出,并计算所有调用,推送和堆栈帧。然后你需要重复调用树中的所有函数,找到最长的路径,以及它的总和。
如果你可以在调试器中运行该函数,只需在调用函数之前记下堆栈指针的值,逐步进入函数,直到你处于最深处,并记下堆栈指针的值。这为您提供了一个真实的数字。
如果你可以重新编译整个函数树,添加一个简单的序言和结尾宏,它记录全局变量中堆栈指针的低水位标记。重新编译整个项目并运行它。这为您提供了许多迭代的真实数字。
如果您的函数调用您没有可见性的第三方代码,问题会变得更加棘手。为此,您可以简单地将堆栈存储器设置为低于当前堆栈点的40(或左右)字节,调用该函数,然后查找自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);
}
请记住,硬件中断也会随机消耗堆栈。 编辑:这可能不是用户流程的问题。