技术开发 频道

内存泄漏检测程序的算法优化

  3、 优化原因

  内存泄漏检测动态链接库(ResLeak)的设计目标之一:不仅可以在Windows环境下使用,也可以在Linux环境下使用,而且对达梦服务器的性能影响很低。在Windows环境下,通过调用Windows的库函数,可以方便快速的获取堆栈跟踪信息,达梦服务器调用该库带来的性能影响可以忽略不计。在Linux环境下,达梦服务器申请内存成功后,在内存泄漏检测动态链接库的add_leak_point接口中通过调用backtrace函数和backtrace_symbols函数来获取堆栈跟踪信息,获取的每一层堆栈信息格式如下所示:

  ./应用程序名 [函数地址]

  具体的例子如下:

./dmServer [0x804869c]

  也就是说获取的只是堆栈跟踪函数的内存地址,并不是我们想要的具体函数名称和源代码定位行数。要想获取这些信息,还必须执行终端命令来进行转换:

addr2line -f 0x804869c -e dmServer > filename1

  该命令把指定应用程序对应内存地址的具体函数信息保存到filename1文件中,保存信息的格式如下例所示:

os_malloc
/root/src/pub/err.c:69

  filename1文件中的第一行保存的是具体的函数名称,第二行是源代码的定位行数。因此,在Linux环境下获取堆栈跟踪信息的步骤应该包括以下几步:

  1) 调用backtrace函数和backtrace_symbols函数获取堆栈地址信息;

  2) 从每一层的堆栈地址信息中解析出函数的内存地址;

  3) 调用system函数执行addr2line命令,把内存地址转换成具体的函数信息,保存到临时文件中;

  4) 读取临时文件,从中解析出函数名称和源代码定位信息,保存到信息结点中。

  具体的代码如下:

void* trace[ MAX_LEVEL ];
char** messages = NULL;
int trace_size = 0;
int i=0;
trace_size
= backtrace( trace, MAX_LEVEL );
messages
= backtrace_symbols( trace, trace_size );  //获取堆栈地址信息
for( i = 0; i < trace_size && i< MAX_LEVEL; i++ )
{
 p_leak1
->callstack [i] = (void *)malloc(strlen(messages[i])+1);
 sprintf(p_leak1
->callstack [i],"%s",messages[i]); //保存中间结果-函数地址信息
 getfunc(p_leak1
->callstack [i]);// 执行getfunc子函数转换成具体函数信息
}
 p_leak1
->level = i;

  采用此逻辑实现内存泄漏检测动态链接库(ResLeak)后,在Linux环境下进行调用测试,发现达梦服务器在启动阶段由于频繁分配内存导致大量调用add_leak_point接口来向信息结点链表中插入新的结点,启动速度极慢。在Windows环境下正常启动只需要一分钟左右,而在Linux环境下,却需要一小时甚至更多时间,程序性能极其低下。因此,必须想办法对程序算法进行优化处理,否则内存泄漏检测动态链接库就无法在Linux下正常使用。

0
相关文章