| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> C++内存泄露 -> 正文阅读 |
|
[C++知识库]C++内存泄露 |
一、内存泄漏是什么内存泄漏,是指在程序代码中动态申请的、堆上的内存 由于某种原因、在使用后没有被释放,进而造成内存的浪费。 少部分的内存泄漏不会影响程序的正常运行,不过如果是持续的内存泄漏会耗光系统内存,最终会导致程序卡死甚至系统崩溃。为了避免系统崩溃,在无法申请到内存的时候,要果断调用exit()函数主动杀死进程,而不是试图挽救这个进程。 二、如何察觉到内存泄漏如果程序在正常地使用过程中,占用的内存随着时间推移不断增长,一般就说明存在内存泄漏的情况。也可以使用专门的工具来检测程序中的内存泄漏: 在vc++中可以使用 VLD(Visual LeakDetector) 进行检测,VLD 是一个免费开源的工具,只需要包含头文件即可,并且可以获取到内存泄漏的代码文件行号。 Tencent tMem Monitor是腾讯推出的一款运行时C/C++内存泄漏检测工具。TMM认为在进程退出时,堆内存中没有被释放且没有指针指向的无主内存块即为内存泄漏,并进而引入垃圾回收(GC, Garbage Collection)机制,在进程退出时检测出堆内存中所有没有被引用的内存单元,因而内存泄露检测准确率为100%。 gperftools 是 google 开源的一组套件,提供了高性能的、支持多线程的 malloc 实现,以及一组优秀的性能分析工具。gperftools 的 heap chacker 组件可以用于检测 C++ 程序中的内存泄露问题,它可以在不重启程序的情况下,进行内存泄露检查。 三、内存泄漏是如何产生的最简单的解释就是,主动申请的内存块在使用后没有被释放。最常见的几种造成内存泄漏的原因有: 1. malloc/new申请的内存没有主动释放使用 malloc 申请的内存要主动调用 free,new 申请的内存要主动调用 delete,否则就会导致内存泄漏。例如下面代码中的内存 ptr 在申请后没有被释放就造成了内存泄漏。
2. 使用free释放new申请的内存malloc/free以及new/delete必须是各自成对出现,如果混用,就会导致意想不到的情况出现。另外,如果用delete释放void指针指向的对象同样也会造成内存泄露。 3. 使用delete去删除数组使用 new 申请的数组,释放的时候要用 delete[] 删除,如果错误地使用 delete 删除,就会造成内存泄漏。
4. 基类的析构函数没有定义为虚函数当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源没有正确是释放,因此造成内存泄露。例如下面代码中析构函数 ~A() 不是virtual,在调用 delete pa 的时候就不会调用子类 B 的析构函数,该对象中子类 B 中的内存无法被释放干净。
四、该如何避免内存泄漏内存泄漏会导致程序不稳定,如果是在一个非常复杂的项目中去排查一处内存泄漏的地方,也是非常让人头疼的一件事情,与其研究如何更好地解决问题,不如研究如何避免问题的发生。 在写代码的时候多花些时间保证代码的质量,往往是一种更为高效的方式。前期如果为了赶进度,匆匆写下的代码,在后期用则需要更多的时间去填坑,这就是“欲速则不达”。 为了避免内存泄漏的情况,有几种方法可以尝试。 1. 谨慎使用动态内存在编写代码的时候,对动态内存保持警惕,保证每一块儿申请的内存都要得到释放。特别是在每个 return 之前,要想一想是否还有内存没有被释放,如果这里不释放,在其他地方是否会正常释放。 这是一种靠脑袋的方式,需要编写代码的时候时刻保持敏感,但是脑袋往往是不可靠的。最好选用其他的方式来保障。 2. 使用RAIIRAII,全称资源获取即初始化(英语:Resource Acquisition Is Initialization),通过对象的初始化实现资源获取,通过对象的销毁实现资源的释放,我们所说的资源就是动态内存。RAII要求,资源的有效期与持有资源的对象的生命周期严格绑定,通过构造函数获取资源,通过析构函数释放资源,这样就有效地避免了资源泄漏。 例如下面的例子中,通过 MemBlock 类的构造函数分配内存,通过析构函数释放内存,在需要使用动态内存的地方只需要定义一个 MemBlock 对象 buff,通过成员函数 get() 获取内存地址,使用之后无需手动释放内存,在 buff 离开作用域的时候,buff 会被自动释放(调用析构函数),在析构函数中调用 free 释放 buff 所持有的内存。如果在所有需要使用内存的地方都用这种方法,只要保证 MemBlock 对象能被析构,就不会造成内存泄漏。
当然,如果通过 new 来申请 MemBlock 对象,就又会存在该对象没有被释放的风险,这个时候使用智能指针来存档 MemBlock 对象将会是一个好的选择。 3. 使用智能指针就是为了解决动态内存的使用安全问题,C++ 才引入了智能指针的概念,智能指针除了具备普通内存的所有功能之外,还可以保证所指向的对象不再被被引用的时候,自动释放该对象。就这样 C++ 开发人员可以通过智能指针挪走头顶的达摩克里斯之剑。 标准库提供的两种智能指针 shared_ptr 和 unique_ptr,二者的区别在于管理底层指针的方法不同,shared_ptr允许多个指针指向同一个对象,内部通过引用计数知道对象被几个指针引用,当引用为0的时候就是该对象将被释放的时候;unique_ptr 则“独占”所指向的对象,它不能被赋值,智能通过 std::move() 将引用转移到另一个 unique_ptr。标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,作为观察者指向 shared_ptr 所管理的对象,不会改变对象的引用计数。这三种智能指针都定义在memory头文件中。 使用智能指针直接管理动态内存,在使用之后不需要手动释放,当这段内存不再被引用的时候,这段内存会被调用 free 函数来释放,free函数是作为自定义的释放函数传给智能指针的,如果是其他类型的对象,不需要传入释放函数,会默认调用类型的析构函数来释放。
使用智能指针结合RAII管理动态内存,通过 RAII 将内存的申请和释放进行封装,再使用智能指针管理封装后的类对象。这样实现对内存的自动管理,可以像使用 C# 或 Java 一样使用内存,无需担心内存的释放问题。结合上面定义的 MemBlock 类:
内存的申请释放通过MemBlock类的构造函数和析构函数实现,MemBlock 类的对象 mem 使用智能指针管理,不再使用内存的时候,mem 的引用计数变为0,自动被释放析构,同时 free 掉其拥有的内存。 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 0:37:26- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |