项目:迅雷下载库内存泄露检测
作者:曾金龙
供职:深圳迅雷网络技术股份有限公司
领域:迅雷下载库
时间:2014-07-26
迅雷的移动下载库是用C语言编写的,为了能够横跨欧亚非拉(ios,android,还有诺基亚的什么系统来着,对了symban)和性能,我们厂的下载库就选择了C,然后在C代码里面使用各种宏,预编译等来达到一 个下载库,多平台使用。不过平台相关的都已经约束在了一个叫common的库里面的一个子模块里面了。这极大的解放了我厂的码农朋友。
但是C毕竟是C,在聊起C的时候,我们组最喜欢说的是,我们权限最大,想干啥干啥。最悲痛的是,测试妹子过来了,然后说各种问题,但是logcat都捕获不到,或者有时候崩溃了但是没有tombstone,等。其实,C最大的危险就是内存泄露。。。因为C的内存泄露,我和测试妹子的感情最近变得更加的亲密而又微妙。。。
老大发话了,必须解决所有C内存泄露。。。
在我下写我负责的数据存储模块的时候,我就动了一个小技巧,就能够把本模块的内存泄露全部给检测出来,而我这朴素的思想其实也是其他内存泄露检测工具的灵魂,只是,老大嫌我的太朴素了。
我的做法很简单,每次malloc内存的时候不是调用系统的malloc,而是调用我的malloc,取名为fc_malloc(因为我的模块叫file_cache),free则调用fc_free。具体代码如下:
#define fc_malloc(size) fc_malloc_imp(size,__FILE__,__LINE__) #define fc_free(ptr) fc_free_imp(ptr) typedef struct mem_log{ void* addr; char* file; int line; }memlog; #ifdef _LOGGER static list g_mem_list #endif // _LOGGER void init_module() { #ifdef _LOGGER list_init(&g_mem_list); #endif } void uninit_module() { #ifdef _LOGGER list_for_each(g_mem_list,v) { memlog* iterm=(memlog*)LIST_VALUE(v); printf("%s,%d,%x\n",iterm->file,iterm->line,iterm->addr);//output the memory not free.. free(iterm); } list_clear(&g_mem_list); #endif // _LOGGER } void* fc_malloc_imp(size_t size,char* file,int line) { void* ptr=malloc(size); #ifdef _LOGGER if(ptr!=NULL) { memlog* iterm = (memlog*)malloc(sizeof(memlog)); iterm->addr=ptr; iterm->file=file; iterm->line=line; list_insert(&g_mem_list,iterm); } #endif // _LOGGER return ptr; } void fc_free_imp(void* ptr) { #ifdef _LOGGER if(ptr!=NULL) { list_erase_by_addr(&g_mem_list,ptr);//in this funciton we need free the memlog iterm memory. } #endif // _LOGGER free(ptr); }
却是很简单,说白了就是用一个链表去等级下每次malloc的地址信息,当然为了好定位,包含文件和行信息,然后在模块卸载的时候,就可以打印出哪些内存还没有被释放。这样对于检查内存泄露,已经达到目的了,很简单吧。有用的东西都是很简单,但很巧妙。
在老大说我应该去看下现有的内存检测工具之前,我觉得我 的这个“创作”已经帮了我解决了所有的内存泄露问题,至少,我和测试妹子的关系从聊bug转移到聊哪件衣服好看了,恩,不错。