持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天。
内存泄漏是指由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。
我们平时开发过程中不可避免的会遇到内存泄漏问题,你是如何排查的呢?估计你是使用下面这几个工具吧?
-
valgrind
-
mtrace
-
dmalloc
-
ccmalloc
-
memwatch
-
debug_new
这里向大家推荐新的一个排查内存泄漏的工具:AddressSanitizer(ASan),该工具为gcc自带,4.8以上版本都可以使用,支持Linux、OS、Android等多种平台,不止可以检测内存泄漏,它其实是一个内存错误检测工具,可以检测的问题有:
-
内存泄漏
-
堆栈和全局内存越界访问
-
free后继续使用
-
局部内存被外层使用
-
Initialization order bugs(中文不知道怎么翻译才好,后面有代码举例,重要)
使用方法直接看我下面的代码:
检测内存泄漏
内存泄漏代码:
#include <stdlib.h>
编译and输出:
g++ -fsanitize=address -g test_leak.cc && ./a.out
编译方式很简单,只需要添加-fsanitize=address -g就可以检测出具体产生内存泄漏的位置以及泄漏空间的大小。
检测堆栈内存越界访问
示例:
#include <iostream>
编译and输出:
g++ -fsanitize=address -g test_leak.cc && ./a.out
可以方便定位到堆栈内存越界访问的错误。
全局内存越界访问:
示例:
#include <iostream>
编译and输出:
g++ -fsanitize=address -g test_leak.cc && ./a.out
局部内存被外层使用
示例:
#include <iostream>
编译and输出:
g++ -fsanitize=address -g test_leak.cc && ./a.out
free后被使用
示例:
#include <iostream>
编译and输出:
g++ -fsanitize=address -g test_leak.cc && ./a.out
Initialization order bugs
示例,这里有两个文件:
// test_memory1.cc
// test_memory2.cc
第一种编译方式输出如下:
g++ test_memory1.cc test_memory2.cc && ./a.out
第二种编译方式输出如下:
g++ test_memory2.cc test_memory1.cc && ./a.out
这种问题我们平时编程过程中可以都不会太注意,然而通过ASan可以检测出这种潜在的bug:
编译and输出:
g++ -fsanitize=address -g test_memory1.cc test_memory2.cc
注意:这里在运行程序前需要添加环境变量:
ASAN_OPTIONS=check_initialization_order=true:strict_init_order=true
小总结
ASan是个很好的检测内存问题的工具,不需要配置环境,使用还方便,编译时只需要-fsanitize=address -g就可以,运行程序时候可以选择添加对应的ASAN_OPTIONS环境变量就可以检测出很多内存问题。它的错误信息也很有用,明确指出当前是什么类型的内存错误,如:
-
detected memory leaks
-
heap-buffer-overflow
-
stack-buffer-overflow
-
global-buffer-overflow
-
heap-use-after-free
-
initialization-order-fiasco
具体可以看google的官方文档:github.com/google/sani…