我即将在我的应用程序中删除“尽可能多的”动态堆分配,我想知道如何确保我没有错过任何内容。
目前,我正在寻找一种方法来轻松甚至自动判断代码的任何(或哪些)部分可能会调用以下标准实现new
/delete
or malloc
/free
无需动态跟踪分配(即通过静态代码分析或来自编译器/链接器的反馈)。
很容易发现(或搜索)直接调用的代码new
or malloc
当然:
int main() {
auto s = new std::string();
delete s;
}
以防分配隐藏在第 3 方库深处或不太明显的情况(例如throw
)我仍然可以在我的二进制文件中搜索新/删除的损坏符号:
g++ main.cpp
nm a.out | grep -E "_Znwm|_Znam|_Znwj|_Znaj|_ZdlPv|_ZdaPv|malloc|free"
U _ZdlPvm@@CXXABI_1.3.9
U _Znwm@@GLIBCXX_3.4
但这种方法只会发现direct的用途new/delete/malloc/free
。如果我的代码(或第 3 方的东西)使用标准库,您将无法通过调用来检测它nm
:
int main() {
std::string a;
for(int i = 0; i < 100; ++i) {
a += "data ";
}
}
我当前的方法是链接到静态标准库(-static-libgcc
/ -static-libstdc++
)并查看是否有引用new
/delete
at all在整个二进制文件中:
g++ -static-libgcc -static-libstdc++ main.cpp
nm a.out | grep -E "_Znwm|_Znam|_Znwj|_Znaj|_ZdlPv|_ZdaPv|malloc|free"
0000000000471fd0 T __cxa_free_dependent_exception
0000000000471f30 T __cxa_free_exception
U free@@GLIBC_2.2.5
U __freelocale@@GLIBC_2.2.5
U malloc@@GLIBC_2.2.5
0000000000471b20 T _ZdlPv
0000000000491bf0 T _ZdlPvm
0000000000471bc0 t _ZN12_GLOBAL__N_14pool4freeEPv.constprop.2
0000000000402a20 t _ZN12_GLOBAL__N_14pool4freeEPv.constprop.2.cold.5
0000000000471e80 T _ZN9__gnu_cxx9__freeresEv
0000000000472240 T _Znwm
0000000000491c00 T _ZnwmRKSt9nothrow_t
0000000000403f37 t _ZnwmRKSt9nothrow_t.cold.0
这种方法适用于小型二进制文件,您可以在其中设法拥有zero堆分配,但只要您允许some分配(例如,在仅执行一次的代码中或在错误情况下,因此很难将其分离的代码might分配堆内存和不会分配的东西。
在最好的情况下,我目前可以想象编译器或静态代码分析器为我提供源代码中的位置列表,这可能会导致动态堆分配。我可以定期检查/过滤此列表,以找出在我的设置中正常的情况(例如引导代码或错误处理)以及我必须重构的情况(例如通过提供特殊的分配器)。
您的方法、工具和经验是什么?