我有一个现有项目,我们为开发人员编译DEBUG(和-O0,所以lldb有意义)。但是我有一个功能,特别是当使用-O0时气球的大小:
-O2 -Wframe-larger-than=100
warning: stack frame size of 168 bytes in function 'dsl_scan_visitbp'
-O0 -Wframe-larger-than=100
warning: stack frame size of 1160 bytes in function 'dsl_scan_visitbp'
并进行一些递归,可能会非常浪费堆栈(内核中有16K堆栈)。
首先要检查的是任何局部变量,但我相信只有两个:
dsl_pool_t *dp = scn->scn_dp;
blkptr_t *bp_toread = NULL;
如果要查看整个功能:https://github.com/openzfs/zfs/blob/master/module/zfs/dsl_scan.c#L1908(Linux资料来源,但处理Apple clang端口)
该源文件中有一堆alwaysinline
,也可能在这里播放。
但是我很好奇为什么-O0会使它变得如此之大?
然后该怎么办,我看不到任何Apple-clang #pragmas在一个文件或一个文件的源文件中打开(打开)优化(仅关闭优化)。如果我知道原因是什么,也许我可以用另一个编译指示来控制该特定问题。
[我现在看到的唯一解决方案是在Makefile中对dsl_scan.c
进行不同的处理,以便仅该文件始终获得-O2。但这有点乏味。
由于我对代码库不熟悉,所以我看不到任何明显的变量会占用大量堆栈空间。但是,我注意到函数(包括always_inline
d)很长。通常,在调试版本中,无论范围如何,都会在堆栈帧中为every变量和临时表达式结果分配一个unique空间。因此,即使2个变量的生存期不重叠(例如,在if
块中声明了一个变量,在else
块中声明了另一个变量),也将在内存中为其分配单独的空间。因此,即使存在很多小的短期变量和临时值,这也可能加起来。
您最好在调试版本中禁用此函数调用的所有函数中的always_inline
属性,因为这样可以避免为所有可能的执行分支预先分配内存,即使它们从未被使用过,或者即使它们在递归不涉及的函数。