于“检测内存错误”这无异于所以法,我们得以据此 valgrind 或者 dmalloc 或者 efence 来上平等的目的,专业的除错工具比自己山寨一个内存检查器要拄谱。

可是我真的好再写了 malloc 的庞大,比较便宜好用,源文件为酷短.

 


以应用程序中替换Linux中Glibc的malloc的季种艺术
http://blog.csdn.net/littlefang/article/details/6052563

 

        
打算优化系统的内存分配,接管glibc提供的内存管理,但是任何工程的代码量很老,使用malloc、realloc、calloc和free的地方所在都是,如果协调写好之接口需要重新命名所有的调用,先不说工作量,部分无权限查看代码的.a文件就行不必然矣。所以用替换掉系统的malloc,保证原有调用的称号不更换。经过尝试,共有四栽艺术可轮换,各发生利弊吧。

方案1 应用环境变量LD_PRELOAD

        
环境变量LD_PRELOAD指定程序运行时优先加载的动态连接库,这个动态链接库中之记优先级是参天的。标准C的各种函数都是存放于libc.so.6的文书中,在程序运行时自动链接。使用LD_PRELOAD后,自己编写的malloc的加载顺序高于glibc中的malloc,这样虽落实了替换。用法:

         [littlefang]$ LD_PRELOAD=” ./mymalloc.so”

        
这是极端实用的轮换方法,动态链接库加载过程中提供了初始化函数,可以随意的获取系统malloc的句柄,再用它举行更加的管理,Hoard(参见深入Linux的内存管理,关于PTMalloc3、Hoard和TCMalloc)的饶是这么实现的。

方案2  malloc调试变量

        
__malloc_hook是平等组glibc提供的malloc调试变量中的一个,这组变量包括:

 

[cpp:nogutter] view
plaincopyprint?

  1. void *(*__malloc_hook)(size_t size, const void *caller);   
  2.   
  3. void *(*__realloc_hook)(void *ptr, size_t size, const void *caller);   
  4.   
  5. void *(*__memalign_hook)(size_t alignment, size_t size, const void *caller);   
  6.   
  7. void (*__free_hook)(void *ptr, const void *caller);   
  8.   
  9. void (*__malloc_initialize_hook)(void);   
  10.   
  11. void (*__after_morecore_hook)(void);  

 

而你在先后中描绘及”__malloc_hook =
my_malloc_hook;”,之后的malloc调用都见面使my_malloc_hook函数,方便易行。但是及时组调试变量不是线程安全之,当你想就此系统malloc的早晚只得把他们变更回去,多线程调用就得达锁了。因此方案2未怪适用于系统内存优化,勉强用来简单管理线程内存以。

         详细用法请猛击这里

方案3 编译自己之libmalloc.a

        
关于重载glibc的malloc库,ChinaUnix上起这么的座谈:

而本身所以cc -o myprog myprog.c -lmylib,
而休思改缺省的ld的命令执行参数或者linker脚本,不知可可以?

是主意真的比较漂亮,只需要make一坏就OK了,不用转环境变量,省得担心后台运行的题材。后面有人回复给楼主试试,不懂得楼主试了无,我尝试了瞬间。

要是一旦拿系统内存管理起来,首先还是一旦往操作系统申请内存,这个问题对LD_PRELOAD方案特别粗略,链接库加载时虽得管glibc中的malloc加载进来,以后直接调用就可了,如:

real_malloc = dlsym(RTLD_NEXT, “malloc”);

而若而应用好编译的malloc库,在你调用dlsym这个函数时,dlsym会调用dlerror,dlerror会调用calloc,calloc要调用malloc,而你的malloc正在初始化等待dlsym返回中,于是死循环了。有人说,在调用没有初始化完毕的malloc时,返回NULL,我碰了dlsym不信服账,加载可耻的挫败了。在充满世界的搜索dlsym的替代品未果后,我把眼光瞄住了tcmalloc(参见深入Linux的内存管理,关于PTMalloc3、Hoard和TCMalloc)。Tcmalloc使用时索要以链接时添加-ltcmalloc即可,它代码里吗从没动用dlsym,大略了羁押了产它们的代码,它采取mmap从系统得到的内存。

void *mmap(void *addr, size_t len, int prot, int flags, int fildes,
off_t off);

这种方式从页面级就假设对网内存进行管理,Glibc中的malloc就是行使mmap和brk两个函数从程序堆着拿走内存的。无疑,这较用malloc分配的内存复杂了过多。

方案4 链接过程控制

ld中来一个选
–wrap,当找某个符号时,它先先分析__wrap_symbol, 解析不交才去解析symbol。例如:

 

[cpp:nogutter] view
plaincopyprint?

  1. void *__wrap_malloc (size_t c)  
  2.   
  3. {  
  4.   
  5.      printf (“malloc called with %zu/n”, c);  
  6.   
  7.      return __real_malloc (c);  
  8.   
  9. }  

 

当其他文件与汝兑现__wrap_malloc函数的公文链接时利用–wrap malloc
,则有到malloc的调用都是会链接到__wrap_malloc上。只有调用__reall_malloc时才见面调用真正的malloc。

 

[cpp:nogutter] view
plaincopyprint?

  1. #include <stdio.h>  
  2.   
  3. #include <stdlib.h>  
  4.   
  5.    
  6.   
  7. void *__real_malloc(size_t);  
  8.   
  9.    
  10.   
  11. void *__wrap_malloc(size_t c)  
  12.   
  13. {  
  14.   
  15.         printf(“My MALLOC called: %d/n”, c);  
  16.   
  17.         return __real_malloc(c);  
  18.   
  19. }  
  20.   
  21.    
  22.   
  23. int main (int argc, char *argv[])  
  24.   
  25. {  
  26.   
  27.         void *ptr = malloc(12);  
  28.   
  29.    
  30.   
  31.         return 0;  
  32.   
  33. }  

 

编译 

[littlefang]$ gcc wrap.c -o wrap -Wl,-wrap,malloc

运行 

[littlefang]$ ./wrap

My MALLOC called: 12

Gcc或g++编译使用
–Wl选项,以指定链接器参数,比如以替换malloc,free,realloc就设为此

gcc wrap.c -o wrap -Wl,-wrap,malloc  -Wl,-wrap,free  -Wl,-wrap,realloc。

专程要专注的凡,如果你的__wrap_malloc是用C++实现之,千万不要遗忘加上extern
“C”做修饰,不然会现出”undefine reference to __wrap_malloc”。

 

 

 

分享到:

  • 上一篇:深入Linux的内存管理,关于PTMalloc3、Hoard和TCMalloc
  • 下一篇:volatile关键字与原子操作的分别

http://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/  “应用
Valgrind 发现 Linux 程序的内存问题 “

 

以下也转载,原文不知.


决不重载全局 ::operator new()
日期:2011年3月14日 | 来源:看文章 | 编辑9号小组 | 看文章

  总之,第二种植重载方式接近功能再丰富,但事实上跟程序里使用的别 C++
library 很麻烦无缝配合。

  综上,对于现实生活中之 C++ 项目,重载 ::operator new()
几乎没有用武之地,因为非常为难处理好和程序所用之 C++ library
的干,毕竟大多数 library 在统筹之早晚没设想到你晤面重载 ::operator
new() 并强塞给其。

  如果真要定制内存分配,该如何处置?

  替代方式

  很粗略,替换 malloc。如果用,直接从 malloc 层面入手,通过
LD_PRELOAD 来加载一个 .so,其中起 malloc/free 的代实现(drop-in
replacement),这样能够以为 C 和 C++ 代码服务,而且免 C++ 重载
::operator new() 的阴霾角落。

  对于“检测内存错误”这无异用法,我们得就此 valgrind 或者 dmalloc 或者
efence
来达到同等之目的,专业的除错工具比自己山寨一个内存检查器要因谱。

  对于“统计内存以数据”,替换 malloc
同样会获得足够的信息,因为咱们得为此 backtrace() 函数来博调用栈,这正如
new (__FILE__, __LINE__) 的音讯更丰富。比方说而通过分析
(__FILE__, __LINE__) 发现 std::string
大量分红释放内存,有超越预期的开,但是你却休亮代码里啊有在频繁创建与销毁
std::string 对象,因为 (__FILE__, __LINE__)
只能报你尽内层的调用函数。用 backtrace() 能找到真正的倡导调用者。

  对于“性能优化”这无异于就此法,我认为当下眼前的多线程开发中,自己实现一个能打败系统默认的
malloc
的外存分配器是勿现实的。一个通用的外存分配器本来就是闹一定之难度,为多线程程序实现一个平安暨高速之通用(全局)内存分配器超出了一般开发人员的力。不如使用现有的对准多核多线程优化的
malloc,例如 Google tcmalloc 和 Intel TBB 2.2 里的外存分配器。好于这些
allocator 都不是侵入式的,也并非重载 ::operator new()。

  也独立的 class 重载 operator new() 有题目啊?

  与全局 ::operator new() 不同,per-class operator new() 和 operator
delete () 的震慑对若有些得多,它仅仅影响本 class 及其派生类。似乎重载 member
operator new() 是中的。我本着这个持反对态度。

  如果一个 class Node 需要重载 member operator
new(),说明它以了非常之内存分配政策,常见的景况是使了内存池或针对象池。我情愿把立即同实际明显地摆下,而无是转
new Node 的默认行为。具体地说,是故 factory 来创建对象,比如 static
Node* Node::createNode() 或者 static shared_ptr<Node>
Node::createNode();。

  这足以归纳为极其小怪原则:如果自身于代码里读到 Node* p = new
Node,我会觉得其当 heap 上分红了内存,如果 Node class 重载了 member
operator new(),那么自己要是先期仔细读 node.h
才能够发现实际这行代码使用了民用的内存池。为什么非写得明白一点也?写成
Node* p = Node::createNode(),那么我力所能及猜测到 Node::createNode()
肯定做了什么以及 new Node 不等同的政工,免得将来震惊。

  The Zen of Python 说 explicit is better than
implicit,我深信。

  总结:重载 ::operator new()
或许在少数临时的场所能答应只急,但是不该作为一如既往种政策来采取。如果急需,我们可打
malloc 层面着手,彻底而完善地更迭内存分配器。

  参考文献:

  [1] 侯捷,《池內春秋—— Memory Pool
的設計哲學與無痛運用》,《程序员》2002 年第 9 期。