关于内存泄漏的那点事

7 篇文章 0 订阅
7 篇文章 0 订阅

    自己写项目或者程序时,对内存泄漏这块还是少有关心。现在当自己写的项目用到了链表和队列以及栈的时候(可能以前写的都是一些应用型,小的逻辑算法吧),发现内存的使用比较多了,于是就有了对内存的管理。由于项目有小扩大的,所以刚开始并没有考虑这一块,现在再弄,有点亡羊补牢了。不过总归不晚,这里总结一下网上一些资料,方便自己以后查阅,和游客浏览吧。

   1、什么是内存泄漏?

            内存泄漏指的是在程序里动态申请的内存在使用完后,没有进行释放,导致这部分内存没有被系统回收,久而久之,可能导致程序内存不断增大,系统内存不足……引发一系列灾难性后果;(关于程序申请内存分配方式,详见:内存分配方式

    2、关于内存泄漏的监测工具:

       Purify、windbg、Bounds Checker、Coverity、Glow Code、dmalloc、ccmalloc、NJAMD、YAMD、Valgrind、mpatrol、AQtime、CodeGuard等等,可能还有其他的,这里就不一一列举了,自己也是刚接触吧,觉得掌握一到两种工具就行,其他的工具知道有就差不多了,其实目的就是解决问题而已。这里列举的是参考的知乎上整理的。

    3、关于Purify认识和使用

        Purify是主要针对开发阶段的白盒测试,是综合性检测运行时错误的工具,并可以和其他复合应用程序(包括多线程和多进程程序)一起工作。Purify检查每一个内存操作,定位错误发生的地点并提供尽可能详细的信息帮助程序员分析错误发生的原因。

   具体介绍请参考 点击打开链接 。这里是BtatC博主原创的一系列博文,挺有参考意义的,喜欢的可以关注一下博主。

 4、关于Windbg认识与使用

   Windbg简单来说就是一个Windows下对用户态/内核态的程序进行调试,以及对Core Dump文件的分析。对于Crash,资源泄露,死锁等问题的分析,Windbg是一个强有力的利器。

            详细介绍请参考 点击打开链接 。该博客转自与河边一支柳,喜欢的游客可以去关注一波。

    5、关于VS检查内存泄漏的问题

            本人用VS开发比较日常。所以将详细介绍这一节的内容。

            c/c++语言中指针这一块,想必熟悉的人能体会到内存分配重要性。因此我们处理内存,第一件事就是不要有内存泄露。内存泄露不能等到测试的时候,通过长时间运行程序并观察任务管理器的方法来做,这显然已经晚了。幸好Visual C++给了我们一个十分好用的工具:_CrtDumpMemoryLeaks函数。这个函数会在Debug模式下往Visual Studio的output窗口打印出那个时候你new(malloc)了但是还没delete(free)的所有内存块的地址、长度、前N个字节的内容和其他信息。怎么做呢?其实很简单:

 ..........................

#include <crtdbg.h>    //    头文件

 int wmain(vint argc , wchar_t* args[])

 {

    ......................

    // 这里运行程序,并在下面的函数调用之前delete掉所有new的东西
   _CrtDumpMemoryLeaks();
    return 0;

}

我们只需要在注释的地方完成我们程序的功能,然后确信自己已经delete掉所有应该delete的东西,最后_CrtDumpMemoryLeaks()函数调用的时候就可以打印出没被delete的东西了。这个方法十分神奇,因为你只需要在main函数所在的cpp文件这么#include一下,所有的cpp文件里面的new都会受到监视,跟平常所用的用宏把new给换掉的这种破方法截然不同。如果你使用了全局变量的话也要小心,因为全局变量的析构函数是在main函数结束之后才执行的,因此如果在全局变量的析构函数里面delete的东西仍然会被_CrtDumpMemoryLeaks函数当成泄露掉的资源对待。当然本人认为全局变量可以用,但是全局变量的赋值必须在main里面做,释放也是,除非那个全局变量的构造函数没有申请任何内存,所以这也是一个很好的检查方法。

    不过上面也仅仅是一个告诉你有没有内存泄漏的方法罢了。那么如何避免内存泄露呢?当然在设计一些性能要求没有比操作系统更加严格的程序的时候,可以使用以下方法:
    1)、如果构造函数new了一个对象并使用成员指针变量保存的话,那么必须在析构函数delete它,并且不能有为了某些便利而将这个对象的所有权转让出去的事情发生。
    2)、在能使用shared_ptr的时候,尽量使用shared_ptr。shared_ptr只要你不发生循环引用,那么这个东西可以安全地互相传递、随便你放在什么容器里面添加删除、你想放哪里就放在哪里,再也不用考虑这个对象的生命周期问题了。
    3)、不要在有构造函数和析构函数的对象上使用memset(或者memcpy)。如果一个对象需要memset,那么在该对象的构造函数里面memset自己。如果你需要memset一个对象数组,那也在该对象的构造函数里面memset自己。如果你需要memset一个没有构造函数的复杂对象,那么请为他添加一个构造函数,除非那是别人的API提供的东西
    4)、如果一个对象是继承了其他东西,或者某些成员被标记了virtual的话,绝对不要memset。对象是独立的,也就是说父类内部结构的演变不需要对子类负责。哪天父类里面加了一个string成员,被子类一memset,就欲哭无泪了。
    5)、如果需要为一个对象定义构造函数,那么连复制构造函数、operator=重载和析构函数都全部写全。如果不想写复制构造函数和operator=的话,那么用一个空的实现写在private里面,确保任何试图调用这些函数的代码都出现编译错误。

    6)、如果你实在很喜欢C语言的话,那麻烦换一个只支持C不支持C++的编译器,全面杜绝因为误用了C++而导致你的C坏掉的情况出现。

    7)、当你的程序中有全局变量的时候,全局变量的释放示在main函数退出后,所以在main函数最后_CrtDumpMemoryLeaks()会认为全局申请的内存没有释放,造成内存泄漏的假象。如何规避呢?我通常是把全局变量声明成指针在main函数中new 在main函数中delete,然后再调用_CrtDumpMemoryLeaks(),这样就不会误判了。


    什么是循环引用呢?如果两个对象互相使用一个shared_ptr成员变量直接或者间接指向对方的话,就是循环引用了。在这种情况下引用计数会失效,因为就算外边的shared_ptr全释放光了,引用计数也不会是0的。

    本例参考 http://www.cppblog.com/vczh/archive/2010/06/22/118493.html ,并在此基础上整理了一下。

    5、总结

        看到这里不到您是否有所收获,尽然说是转载整理的,所以博客有很多链接,是一些具体介绍,希望有时间的游客可以看看,有助于进一步了解。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CSDN IT狂飙上传的代码均可运行,功能ok的情况下才上传的,直接替换数据即可使用,小白也能轻松上手 【资源说明】 基于MATLAB实现的有限差分法实验报告用MATLAB中的有限差分法计算槽内电位;对比解析法和数值法的异同点;选取一点,绘制收敛曲线;总的三维电位图+使用说明文档 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2020b;若运行有误,根据提示GPT修改;若不,私信博主(问题描述要详细); 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可后台私信博主; 4.1 期刊或参考文献复现 4.2 Matlab程序定制 4.3 科研合作 功率谱估计: 故障诊断分析: 雷达通信:雷达LFM、MIMO、成像、定位、干扰、检测、信号分析、脉冲压缩 滤波估计:SOC估计 目标定位:WSN定位、滤波跟踪、目标定位 生物电信号:肌电信号EMG、脑电信号EEG、心电信号ECG 通信系统:DOA估计、编码译码、变分模态分解、管道泄漏、滤波器、数字信号处理+传输+分析+去噪、数字信号调制、误码率、信号估计、DTMF、信号检测识别融合、LEACH协议、信号检测、水声通信 5、欢迎下载,沟通交流,互相学习,共同进步!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值