使用glibc的MALLOCCHECK
因为是一个内存问题,考虑使用一些内存调试工具来定位问题。因为OB内部对于内存块有自己的缓存,需要去除它的影响。修改OB内存分配器,让它每次都直接调用c库的malloc和free等,不做缓存。然后,可以使用glibc内置的内存块完整性检查功能。
使用这一特性,程序无需重新编译,只需要在运行的时候设置环境变量MALLOCCHECK(注意结尾的下划线)。每当在程序运行过程free内存给glibc时,glibc会检查其隐藏的元数据的完整性,如果发现错误就会立即abort。
用类似下面的命令行启动server程序:
MALLOCCHECK有三种设定,即:
- MALLOCCHECK=0 —– 关闭所有检查.
- MALLOCCHECK=1 —– 当有错误被探测到时,在标准错误输出(stderr)上打印错误信息.
- MALLOCCHECK=2 —– 当有错误被探测到时,不显示错误信息,直接进行中断.
但这个core能带给我们想信息也很少。我们只是找到了另外一种稍高效地重现问题的方法而已。或许最初看到的core的现象是延后显现而已,其实“更早”的时刻内存就被破坏掉了。
valgrind
glibc提供的MALLOCCHECK功能太简单了,有没有更高级点的工具不光能够报告错误,还能分析出问题原因来?我们自然想到了大名鼎鼎的valgrind。用valgrind来检查内存问题,程序也不需要重新编译,只需要使用valgrind来启动:
nohup valgrind –error-limit=no –suppressions=suppress bin/mergeserver -z 45447 -r 10.232.36.183:45401 -p45441 >nohup.out &
默认情况下,当valgrind发现了1000中不同的错误,或者总数超过1000万次错误后,会停止报告错误。加了–error-limit=no以后可以禁止这一特性。–suppressions用来屏蔽掉一些不关心的误报的问题。
AddressSanitizer
- 版本要求: LLVM3.1 或者gcc4.8
bug代码示例
12345678910111213141516171819#include <stdio.h>#include <stdlib.h>int main (int argc,char *argv[]){int i;char* p = (char *)malloc(10);char* pt = p;for (i = 0;i < 10;i++){p[i] = 'z';}free (p);//free(pt);*p = 1;return 0;}编译&运行
12g++ -fsanitize=address test09.cpp -o test09./test09出错提示
[img01]