linux中内存泄漏的检测(五)记录内存泄漏的代码
来源:互联网 发布:阿里云ecs ftp 编辑:程序博客网 时间:2024/06/03 13:27
到目前为止,先后通过wrap malloc、new函数重载和计算指针内存大小的方法,基本上满足了对内存泄漏检测的需要。
如果发现了内存泄漏,那么就要找到内存泄漏的地方并且修正它了。
茫茫代码,如何去找?如果能根据未释放的内存找到申请它的地方就好了。
我们今天就是要做这个事情。
想要根据内存地址查出申请者的信息,那么在一开始申请的时候就要建立地址与申请者之间的映射。
1.内存地址
内存地址,是一个unsigned long型的数值,用void *
来存储也可以。为了避免类型转换,我使用了void *
。
2.申请者信息
申请者的信息比较复杂,不是一个类型可以搞定的。它包括哪些内容呢?
在C情况下,主要是需要知道谁调用了__wrap_malloc
。但在C++情况下,调用__wrap_malloc
的一定是new,这没有什么意义,还需要知道是谁调用了new。再进一步说,new有可能是在构造函数中被调用的,那么很有可能我们真正需要知道的是谁调用了构造函数。
由此可见,仅仅知道是谁调用了__wrap_malloc
不够的,我们需要的是整个栈信息。
整个栈包含了很多内容,在这里,我们只记录栈的深度(int)和每一层的符号名(char **)。符号名在整个程序中是唯一的(不管C还是C++)且相对位置是确定的(动态库除外),当程序结束时再根据符号名反推出调用者的文件名和行号。
为什么不直接获取文件名和行号?
因为求符号名的实现比较简单。
3.映射方式
说到映射,首先想到的是map、hash这样的东西。
但需要说明的是,这里是__wrap_malloc
函数,是每次程序动态分配空间时必然会走到的地方。
这有什么关系呢?想象一下,在由于某个动态申请内存的操作来到了这个函数,而在这个函数里又不小心申请了一次内存,会怎样呢?在-Wl,--wrap,malloc
的作用下又来到了这里,于是开启了“鸡生蛋、蛋生鸡”的死循环中,直到——stack overflow。
所以,在这个函数里能使用的,只能使用栈空间或者全局空间,如果一定要使用堆空间,也必须显示地使用__real_malloc
代替new或者malloc。由于在map、hash中会不可避免地使用动态内存空间的情况,还是放弃吧。
怎么办呢?为了避免节外生枝,我这里使用了最简单但是有点笨的方法——数组。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
4.怎样获取栈中的符号?
gcc给我们提相应的函数,按照要求调用就行。
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
backtrace函数用于获取栈的深度(depth
),以及每一层栈地址(stack
)。 backtrace_symbols
函数根据栈地址返回符号名(symbols
)。
需要注意的是,backtrace_symbols返回的是符号的数组,这个数组的空间是由backtrace_symbols
分配的,但需要调用者释放。
为什么这里backtrace_symbols
分配了内存却没有引起stack overflow呢?以下是我的猜测: backtrace_symbols
函数和wrap机制都是GNU提供的,属性亲戚关系。既然是亲戚,那么大家通融一下,让backtrace_symbols
绕过wrap机制直接使用内存也是有可能的。
源代码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
编译命令:
- 1
- 1
运行:
- 1
- 1
方法分析:
优点:
(1)在程序运行结束时,打印程序内存泄漏情况以及导致泄漏发生的代码所在的文件及行号
(2)C/C++都适用
(3)需要修改产品源代码即可实现功能
(4)对一起链接的所有.o和静态库都有效
缺点:
(1)对动态库不适用
(2)求堆栈信息和求文件名行号是两个操作,不能一次性解决问题
- linux中内存泄漏的检测(五)记录内存泄漏的代码
- linux中内存泄漏的检测(五)记录内存泄漏的代码
- linux中内存泄漏的检测(四)记录泄漏的大小
- linux中内存泄漏的检测(四)记录泄漏的大小
- 内存泄漏的检测
- 内存泄漏的检测
- Solaris中如何检测内核代码的内存泄漏
- linux下检测内存泄漏的工具
- Linux平台下的内存泄漏检测
- Linux平台下的内存泄漏检测
- 浅谈C++中内存泄漏的检测
- 浅谈C++中内存泄漏的检测
- 浅谈C++中内存泄漏的检测
- 浅谈C++中内存泄漏的检测
- C++中内存泄漏的检测
- C++中内存泄漏的检测
- 浅谈C++中内存泄漏的检测
- C++中内存泄漏的检测
- 那些年我犯过的错
- HDU 6105 Gameia 博弈(思维)
- 2017-8-10 Struts2学习笔记二
- C# winform 右键下拉菜单
- 智能手机检测
- linux中内存泄漏的检测(五)记录内存泄漏的代码
- 哈哈哈
- [玩转算法]基础算法思路的应用
- (吴恩达笔记 1-1)——线性回归原理
- 使用Toad插件SQLTracker追踪应用程序与数据库的交互
- C语言 读文件时多读一次最后一行数据的解决办法
- HDU6105 [2017duoxiaolianhe6] Gameia 博弈你个香蕉船
- springmvc 文件下载
- 涨姿势了,蜻蜓FM源码剖析