【发布时间】:2014-06-19 09:43:45
【问题描述】:
有没有办法在 linux 环境中轻松监控堆栈深度?
考虑在 Ubuntu 中使用 gcc 编译的 C 基本应用程序。
如果您不允许动态内存分配(没有 malloc/free-ing)怎么办?
【问题讨论】:
-
类似于stackoverflow.com/questions/1678803/…。并且通过
malloc进行的动态内存分配不使用堆栈空间。它从堆中分配。
有没有办法在 linux 环境中轻松监控堆栈深度?
考虑在 Ubuntu 中使用 gcc 编译的 C 基本应用程序。
如果您不允许动态内存分配(没有 malloc/free-ing)怎么办?
【问题讨论】:
malloc 进行的动态内存分配不使用堆栈空间。它从堆中分配。
编译后你能知道你的最大堆栈深度吗?
否。考虑一个递归函数,它可能会根据输入多次调用自身。在不知道程序的输入是什么的情况下,您无法知道该函数可能被调用多少次,一次在最后一次。
我希望可以确定一些程序的最大堆栈深度,但您无法确定所有程序的最大堆栈深度。
有没有办法在 linux 环境中轻松监控堆栈深度?
我不知道有什么简单的方法可以连续监控堆栈深度,但是您可以使用 gdb 的 -stack-info-depth 命令随时确定堆栈深度。
如果你不允许动态内存分配(没有 malloc/free-ing)怎么办?
这并没有什么不同。考虑一个递归斐波那契函数——它不需要动态分配任何内存,但堆栈帧的数量仍然会根据输入而变化。
【讨论】:
fib() 是一个简单的、广为人知的示例,它不动态分配任何内存。
a() 和b(),其中a 调用b 和b 调用a。确切地说,它们不是递归,但堆栈深度仍会根据编译时未知的条件而变化。接下来,考虑组中可能有 30 或 40 个函数,而不是 2 个函数。只有确定调用图中没有 个循环,才能确定最大堆栈深度。
可以进行调用图分析。图中最长的路径是最大堆栈深度。但是,有一些限制。
对于递归函数,所有的赌注都没有,递归的深度取决于运行时输入,在编译时分析中不可能推断出来。 [可以通过分析调用图并寻找自身边,即具有相同源和目的地的边来检测递归函数的存在。]
此外,如果调用图中存在循环/循环,也会出现同样的问题。 [正如@Caleb 提到的:a()->b()->c()->d()->e()->f()->g()->c()] [使用图论算法,也可以检测循环的存在。]
调用图参考:
【讨论】:
a()->b()->c()->d()->e()->f()->g()->c() 这样的循环。