有没有办法测量特定函数从堆栈中消耗多少内存?

时间:2015-10-16 16:02:32

标签: c++ stack-overflow

有没有办法测量特定c ++函数从调用它到返回时从程序堆栈中消耗多少内存?

3 个答案:

答案 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);
}

请记住,硬件中断也会随机消耗堆栈。 编辑:这可能不是用户流程的问题。