深圳软件测试学习培训:重载new或delete来检测内存泄漏

深圳软件测试学习培训:重载new或delete来检测内存泄漏

1.简述

在日常生活中,例如电脑,还有我们大家每天离不开的手机,用的时间久了,就会发现运行速度越来越快,用方言讲,就是卡的不行啦,电脑或手机出现这种情况,大家势必会感到非常烦躁,有那种摔电脑或手机的冲动。

内存泄漏属于资源泄漏的一种,百度百科将内存泄漏分为四种:常发性内存泄漏、偶发性内存泄漏、一次性内存泄漏和隐式内存泄漏。

常发性指:内存泄漏的代码会被多次执行到。偶发性指:内存泄漏的代码只有在特定的条件下才会执行到。一次性指:内存泄漏的代码只会被执行到一次。隐式指:程序在运行中不断的开辟内存,知道程序结束时才释放内存,本质上虽然没有内存泄漏,但是如果这个程序在连续运行很长时间,会耗尽所有内存,导致系统崩溃。

下面首先介绍内存检测的基本原理,然后给出代码样例,最后说明针对四种内存泄漏进行检测的想法。

  1. 基本原理

内存泄漏就是new出来的内存没有通过delete合理的释放掉。new和delete这两个函数就是关键点。可以重载new和delete,每次new中开辟一块内存就用链表把这个内存的信息保存下来,每次用delete删除一块内存就从链表中删除这块内存的记录。

#include

2 using namespace std;

3 //---------------------------------------------------------------

4 // 内存记录

5 //---------------------------------------------------------------

6 class MemInfo {

7 private:

8 void* ptr;

9 const char* file;

10 unsigned int line;

11 MemInfo* link;

12 friend class MemStack;

13 };

14 //---------------------------------------------------------------

15 // 内存记录栈

16 //---------------------------------------------------------------

17 class MemStack {

18 private:

19 MemInfo* head;

20 public:

21 MemStack():head(NULL) { }

22 ~MemStack() {

23 MemInfo* tmp;

24 while(head != NULL) {

25 free(head->ptr); // 释放泄漏的内存

26 tmp = head->link;

27 free(head);

28 head = tmp;

29 }

30 }

31 void Insert(void* ptr, const char* file, unsigned int line) {

32 MemInfo* node = (MemInfo*)malloc(sizeof(MemInfo));

33 node->ptr = ptr; node->file = file; node->line=line;

34 node->link = head; head = node;

35 }

36 void Delete(void* ptr) {

37 MemInfo* node = head;

38 MemInfo* pre = NULL;

39 while(node != NULL && node->ptr!=ptr) {

40 pre = node;

41 node = node->link;

42 }

43 if(node == NULL)

44 cout << “删除一个没有开辟的内存” << endl;

45 else {

46 if(pre == NULL) // 删除的是head

47 head = node->link;

48 else

49 pre->link = node->link;

50 free(node);

51 }

52 }

53 void Print() {

54 if(head == NULL) {

55 cout << “内存都释放掉了” << endl;

56 return;

57 }

58 cout << “有内存泄露出现” << endl;

59 MemInfo* node = head;

60 while(node != NULL) {

61 cout << "文件名: " << node->file << " , " << "行数: " << node->line << " , "

62 << "地址: " << node->ptr << endl;

63 node = node->link;

64 }

65 }

66 };

67 //---------------------------------------------------------------

68 // 全局对象 mem_stack记录开辟的内存

69 //---------------------------------------------------------------

70 MemStack mem_stack;

71 //---------------------------------------------------------------

72 // 重载new,new[],delete,delete[]

73 //---------------------------------------------------------------

74 void* operator new(size_t size, const char* file, unsigned int line) {

75 void* ptr = malloc(size);

76 mem_stack.Insert(ptr, file, line);

77 return ptr;

78 }

79 void* operator new[](size_t size, const char* file, unsigned int line) {

80 return operator new(size, file, line); // 不能用new

81 }

82 void operator delete(void* ptr) {

83 free(ptr);

84 mem_stack.Delete(ptr);

85 }

86 void operator delete[](void* ptr) {

87 operator delete(ptr);

88 }

89 //---------------------------------------------------------------

90 // 使用宏将带测试代码中的new和delte替换为重载的new和delete

91 //---------------------------------------------------------------

92 #define new new(FILE,LINE)

93 //---------------------------------------------------------------

94 // 待测试代码

95 //---------------------------------------------------------------

96 void bad_code() {

97 int *p = new int;

98 char *q = new char[5];

99 delete []q;

100 }

101

102 void good_code() {

103 int *p = new int;

104 char *q = new char[5];

105 delete p;

106 delete []q;

107 }

108 //---------------------------------------------------------------

109 // 测试过程

110 //---------------------------------------------------------------

111 int main() {

112 good_code();

113 bad_code();

114 mem_stack.Print();

115 system(“PAUSE”);

116 return 0;

117 }

  1. 代码说明

4.1 关于new的参数问题。

对于new int,编译器会解释为new(sizeof(int)),对于new int[5],编译器会解释为new(sizeof(int)*5)。因此使用宏定义预编译后,new int就变为new (FILE,LINE) int,编译器会解释为new(sizeof(int), FILE,LINE)。

4.2 关于MemStack

MemStack内部也是一个链表结构,注意内部实现不能使用new和delete,只能使用malloc和free来实现链表,因为待测代码中的重载new和delete中调用了MemStack的insert和delete函数,如果insert和delete函数也调用重载后的new和delete的话,会构成死循环的,所以直接使用free和malloc比较好。

MemStack中的析构函数,会释放掉泄漏掉的内存。

  1. 使用思考

对于常发性和一次性的内存泄漏代码,直接放入测试就好了。对于偶发性的内存泄漏代码,只要满足特定条件,那么也就转化为常发性或者一次性的内存泄漏了。对于隐式内存泄漏,由于程序是在很长一段时间之后导致内存耗尽,我们需要长时间观察,每隔一段时间比较一下内存的使用量,如果在一个较长的时间内,内存使用量持续增加,那么可以考虑是内存泄漏。不过调试起来可能会比较麻烦,还是需要重新审视程序设计的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值