_t *_mem_mutex_ = NULL;
class global_static
{
public:
global_static()
{
assert( !_mem_mutex_ );
_mem_mutex_ = counter_mutex();
}
~global_static() {_mem_mutex_ = NULL;}
};
/* Dynamic initialization */
const static global_static gs;
这样虽然不能解决问题,但是由于我们在new里校验了_mem_mutex_是否为NULL,至少能发现问题。
既然是C++,那么还可以Construct On First Use Idiom:在使用_mem_mutex_时去检测是否已初始化,未初始化就初始化。而不是像上面那样全局一次初始化,以后都不用检测。
5. 能否统计到STL、BOOST、so、.a等外部代码中的new、delete是否会被重写
STL和BOOST这种很多时候是是模板,也就是源码,和你项目中的代码一样,当然也会被重写。对于so动态链接库,他和程序是分离的。当你的程序加载这个so文件时,它会优先在你的程序里查找他需要的符号,如果找到了,就会优先使用。这和LD_PRELOAD的机制是一样的,因此也是会被重写的。而.a这种静态链接库,在gcc链接时会按你传入的库顺序查找符号,一般来说你项目中的符号都是优先于libgcc这种标准库的,因此也是会被重写的。
要明白这些,要懂得gcc是如何编译、链接一个程序的,尤其是对符号的管理。https://akkadia.org/drepper/dsohowto.pdf
6. 可以用nm来判断是否重写
xzc@xzc-HP-ProBook-4446s:~/Documents/code/test$ nm -C a.out | grep new
0000000000400f60 T test_static_new()
U operator new[](unsigned long)@@GLIBCXX_3.4
0000000000400d34 T operator new(unsigned long)
0000000000401120 r operator new(unsigned long)::__PRETTY_FUNCTION__
T表示text,说明你已经重写了。U表示undefine,表示没有重写,程序运行时,要去库里查找这个符号。
大部分人重写operator new和operator delete的初衷,无非就是检测内存泄漏,或者实现自己的内存管理。对于内存泄漏,通过重写operator new来实现的,可以看http://wyw.dcweb.cn/leakage.htm这里,现在还在维护的项目是https://github.com/adah1972/nvwa,我没用过,但看下逻辑应该还是不错的。而对于在代码中重写operator new来实现内存管理,我倒没见过。毕竟想写一个通用的内存管理不容易,写出来也是一个库了,比如jemalloc这种。