Java检测Linux内存泄漏,linux中内存泄漏的检测(三)定制化的new/delete

《linux中内存泄漏的检测(二)定制化的malloc/free》中的__wrap方法只解决了C的问题,这一节介绍怎么让C++中的new/delete也能方便地插入计数代码。

wrap方法尝试

可不可以使用__wrap_new/__wrap_delete?我们试试看。

我写了这样的测试代码

#include

using namespace std;

int count = 0;

void * __wrap_new(size_t size)

{

count++;

return __real_new(size);

}

void __wrap_delete(void *ptr)

{

count--;

__real_delete(ptr);

}

int main()

{

count = 0;

int *p1 = new int;

int *p2 = new int;

delete p1;

if(count != 0)

cout<

return 0;

}

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

然后这样编译,g++ -o test test.cpp -Wl,--wrap,new -Wl,--wrap,delete,结果

cpptest.cpp: In function ‘void* __wrap_new(size_t)’:

cpptest.cpp:9:27: error: ‘__real_new’ was not declared in this scope

return __real_new(size);

^

cpptest.cpp: In function ‘void __wrap_delete(void*)’:

cpptest.cpp:15:22: error: ‘__real_delete’ was not declared in this scope

__real_delete(ptr);

^

1

2

3

4

5

6

7

8

看来这种方法不可行,这要从new和malloc的区别说起。

new VS. malloc

malloc很好理解,它的作用就是分配一段指定大小的内存空间。

而new的工作分为两步:

第一步也是分配一段指定大小的内存空间,这一步与malloc相同,它有一个专用的名字,叫operator new

第二步是将分配到的内存以指定的方式初始化化,这是malloc所没有的,它也有一个专用的名字,叫placement new

步骤    作用    与malloc的关系    是否可以重载    怎样使用

operator new    分配一段指定大小的空间    相当于malloc    可以重载    可以单独调用,如class *pA = operator new(100),相当于class *pA = malloc(100);

placement new    将一段空间以指定的方式初始化    malloc不能提供这样的功能    不能重载    可以把空间的指针作为参数传入,单独调用这一行为执行初始化操作,如class *pA = new(buf) class();,相当于使用class::class()初始化buf这段内存

关于operator new和placement new和更多细节,可以参考更多文章,但显然new的功能非常复杂,并不是一个__wrap_new(size_t size)能解决的。

operator new 重载

new的功能虽然复杂,但我们所关心的只是其中与分配内存相关的部分,也就是operator new。幸好,它可以重载。

C++支持重载,我们可以重载new中的operater new,在其中加入计数功能,并通过malloc实现内存申请。

#include

using namespace std;

#include

#include

int count = 0;

void * operator new(size_t size)

{

count++;

return malloc(size);

}

void operator delete(void *ptr)

{

count--;

free(ptr);

}

int main()

{

count = 0;

int *p1 = new int;

int *p2 = new int;

delete p1;

if(count != 0)

cout<

return 0;

}

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

既然new也是通过调用malloc实现的,那么也不用operator new和malloc分别统计了,只需要统计malloc就行了。因为__wrap_symbol和__real_symbol都是C函数,所有要使用extern "C"。

#include

using namespace std;

#include

#include

int count = 0;

extern "C"

{

void* __real_malloc(int c);

void * __wrap_malloc(int size)

{

count++;

return __real_malloc(size);

}

void __real_free(void *ptr);

void __wrap_free(void *ptr)

{

count--;

__real_free(ptr);

}

}

void * operator new(size_t size)

{

return malloc(size);

}

void operator delete(void *ptr)

{

free(ptr);

}

int main()

{

count = 0;

int *p1 = new int(3);

int *p2 = new int(4);

cout<

delete p1;

if(count != 0)

cout<

return 0;

}

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

分析

优点

(1)使用方便 — 不需要改产品代码,只需要修改编译选项即可完成。

(2)范围全面 — wrap是个链接选项,对所有通过__wrap_malloc和__wrap_free链接到一起的文件都起作用,不论是静态库还是动态库。

(3)c的检测与c++的检测无缝兼容

缺点

(1)该方法要求运行结束时对运行中产生的打印分析才能知道结果。

(2)只能检测是否泄漏,却没有具体信息,比如泄漏了多少空间

(3)不能说明是哪一行代码引起了泄漏

(4)这一方法虽然解决了C++的替换问题,却引入了新的问题。因为在C++中对于同一指针申请和释放,申请和释放的大小却有可能不相等,导致有些情况的内存泄漏检测不到。比如(a)申请子类而析构父类(b)申请数组而释放数组第一项

改进

欲知如何解决,且看下回分解

---------------------

作者:windmissing

来源:CSDN

原文:https://blog.csdn.net/mishifangxiangdefeng/article/details/50552710

版权声明:本文为博主原创文章,转载请附上博文链接!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值