HeLei Blog

内存问题定位

使用glibc的MALLOCCHECK

因为是一个内存问题,考虑使用一些内存调试工具来定位问题。因为OB内部对于内存块有自己的缓存,需要去除它的影响。修改OB内存分配器,让它每次都直接调用c库的malloc和free等,不做缓存。然后,可以使用glibc内置的内存块完整性检查功能。

使用这一特性,程序无需重新编译,只需要在运行的时候设置环境变量MALLOCCHECK(注意结尾的下划线)。每当在程序运行过程free内存给glibc时,glibc会检查其隐藏的元数据的完整性,如果发现错误就会立即abort。

用类似下面的命令行启动server程序:

1
2
export MALLOC_CHECK_=2
./test

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

  1. 版本要求: LLVM3.1 或者gcc4.8
  2. bug代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #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;
    }
  3. 编译&运行

    1
    2
    g++ -fsanitize=address test09.cpp -o test09
    ./test09
  4. 出错提示
    [img01]

坚持原创技术分享,您的支持将鼓励我继续创作!