编程语言应用

首页 » 常识 » 诊断 » 深入理解应用Valgrind发现
TUhjnbcbe - 2021/4/8 20:00:00
皮肤病北京哪家医院好         http://m.39.net/pf/a_4781490.html
来源:杨经原文  常见的内存动态管理错误包括:

申请和释放不一致

由于C++兼容C,而C与C++的内存申请和释放函数是不同的,因此在C++程序中,就有两套动态内存管理函数。一条不变的规则就是采用C方式申请的内存就用C方式释放;用C++方式申请的内存,用C++方式释放。也就是用malloc/alloc/realloc方式申请的内存,用free释放;用new方式申请的内存用delete释放。在上述程序中,用malloc方式申请了内存却用delete来释放,虽然这在很多情况下不会有问题,但这绝对是潜在的问题。

申请和释放不匹配

申请了多少内存,在使用完成后就要释放多少。如果没有释放,或者少释放了就是内存泄露;多释放了也会产生问题。上述程序中,指针p和pt指向的是同一块内存,却被先后释放两次。

释放后仍然读写

本质上说,系统会在堆上维护一个动态内存链表,如果被释放,就意味着该块内存可以继续被分配给其他部分,如果内存被释放后再访问,就可能覆盖其他部分的信息,这是一种严重的错误,上述程序第16行中就在释放后仍然写这块内存。

结果分析:

假设这个文件名为badmac.cpp,生成的可执行程序为badmac,用memcheck对其进行测试,输出如下。

输出结果显示,第14行分配和释放函数不一致;第16行发生非法写操作,也就是往释放后的内存地址写值;第17行释放内存函数无效。准确地发现了上述三个问题。

内存泄露

问题描述:

内存泄露(Memoryleak)指的是,在程序中动态申请的内存,在使用完后既没有释放,又无法被程序的其他部分访问。内存泄露是在开发大型程序中最令人头疼的问题,以至于有人说,内存泄露是无法避免的。其实不然,防止内存泄露要从良好的编程习惯做起,另外重要的一点就是要加强单元测试(UnitTest),而memcheck就是这样一款优秀的工具。

下面是一个比较典型的内存泄露案例。main函数调用了mk函数生成树结点,可是在调用完成之后,却没有相应的函数:nodefr释放内存,这样内存中的这个树结构就无法被其他部分访问,造成了内存泄露。

在一个单独的函数中,每个人的内存泄露意识都是比较强的。但很多情况下,我们都会对malloc/free或new/delete做一些包装,以符合我们特定的需要,无法做到在一个函数中既使用又释放。这个例子也说明了内存泄露最容易发生的地方:即两个部分的接口部分,一个函数申请内存,一个函数释放内存。并且这些函数由不同的人开发、使用,这样造成内存泄露的可能性就比较大了。这需要养成良好的单元测试习惯,将内存泄露消灭在初始阶段。

结果分析:

假设上述文件名位tree.h,tree.cpp,badleak.cpp,生成的可执行程序为badleak,用memcheck对其进行测试,输出如下。

该示例程序是生成一棵树的过程,每个树节点的大小为12(考虑内存对齐),共8个节点。从上述输出可以看出,所有的内存泄露都被发现。Memcheck将内存泄露分为两种,一种是可能的内存泄露(Possiblylost),另外一种是确定的内存泄露(Definitelylost)。Possiblylost是指仍然存在某个指针能够访问某块内存,但该指针指向的已经不是该内存首地址。Definitelylost是指已经不能够访问这块内存。而Definitelylost又分为两种:直接的(direct)和间接的(indirect)。直接和间接的区别就是,直接是没有任何指针指向该内存,间接是指指向该内存的指针都位于内存泄露处。在上述的例子中,根节点是directlylost,而其他节点是indirectlylost。

总结

本文介绍了valgrind的体系结构,并重点介绍了其应用最广泛的工具:memcheck。阐述了memcheck发现内存问题的基本原理,基本使用方法,以及利用memcheck如何发现目前开发中最广泛的五大类内存问题。在项目中尽早的发现内存问题,能够极大地提高开发效率,valgrind就是能够帮助你实现这一目标的出色工具。

Vanilla社区发起?晨读计划?,每天坚持积累一点,今天的努力至少让我们比昨天更进一步。

?晨读计划?期待你的加入......

Vanilla:基于OpenResty的高性能Web应用开发框架

我们的-OpenResty我们的、、

晨读计划

/02/25

预览时标签不可点收录于话题#个上一篇下一篇
1
查看完整版本: 深入理解应用Valgrind发现