目录
前言一个简单的内存泄漏检查内存泄露的方法方法内存泄漏时,内存的消耗没有内存泄露时的内存消耗
前言
这两天抽空把之前买的这门课给看了看,课程很好,有兴趣的也可以看一看:
具体的课程总结过几天写一写,这篇推送就说一下从这课上学到的一个技巧吧:一个检查内存泄露的方法。
这个方法呢,我觉得应该是用在开发阶段的,就是每当我们写好一个模块或者一个功能时,就检查一下,确保无误在接着往下做。
网上也有一些检查内存泄漏的工具,一搜一大堆资料就出来了,我就不介绍了。
先看一个简单的内存泄漏
#include <iostream>
using namespace std;
void testFunc()
{
char* str = new char[1024];
/// Some options
std::cout << "testFunc end" << std::endl;
}
int main()
{
/// Some options
testFunc();
/// Some options
return 0;
}
在 testFunc 函数中 我在堆中
开辟了 1024 字节的内存,但是程序结束时我并没有释放它,这样就堆中的这个 1024字节的内存 就一直被占用着,所以就造成了内存泄漏。
这种简单的内存泄露问题,学过C++的一眼就能看出来,为了避免这样的问题发生,我们一般用智能指针,或者记得 delete / delete[],像下面这样:
#include <iostream>
#include <memory>
using namespace std;
void testFunc()
{
char* str = new char[1024];
/// Some options
delete[] str;
std::cout << "testFunc end" << std::endl;
}
但是,像下面的这样的代码呢,不了解这个库的话可能看不出来有内存泄漏:
其实也不复杂,这些都是 <Python.h>
里面的东西,用C++给Python做拓展库 或者 C++调用Python脚本时会用。
Python中的垃圾回收机制主要是看变量的引用计数,如果引用计数为0时再销毁,我们在做Python的拓展库时,在C++这边是需要我们手动地去增减引用计数的。所以就得控制好这个引用计数,不然一不小心可能就造成了内存泄露了。
由于开发过程中可能会用到一些自己不太熟悉的库,就比如上面的 我就可能忘写上红框里面的代码了,那么就会造成内存泄露了。
上面这两个例子仅仅是调用了一次,并不会消耗太多的内存。但是,在实际的生产中,我们程序可能会是一直在运行的,那么就可能会一直在泄露内存。积少成多,最后宕掉。
为了避免造成内存泄漏的发生,我们在写好一个函数或者一个功能时就及时地对它进行检测,看看是否会造成内存泄露!
检查内存泄露的方法
方法
我们没必要对着代码一行一行地检查,我们只需做一个死循环,不断重复地执行所测试的函数模块,然后打开任务管理器,看内存的增长情况,如果内存在不断地增加那么可能就是内存泄露了。如果有内存泄漏的话,死循环会造成内存快速增长,所以可以判断出是否发生内存泄漏。
如果你用的是VS的话,里面的诊断工具里面有一个进程内存可以看到内存的增长情况,如下。
我平时都用的CLion进行开发,所以就通过看任务管理器了。
如果我们确认了这个模块函数会发生内存泄漏,那么再去一行一行看代码吧。所以平时还是写一点然后就去测试一下!
下面我就拿 VS2017 测试一下
内存泄漏时,观察内存的消耗
代码:
#include "stdafx.h"
#include <iostream>
#include <memory>
using namespace std;
void testFunc()
{
char* str = new char[1024];
/// Some options
std::cout << "testFunc end" << std::endl;
}
int main()
{
/// Some options
while (1)
testFunc();
/// Some options
return 0;
}
下面是几个时间点下的截图(看右侧),可以看到内存的迅速增长:
没有内存泄露时的内存消耗
代码就多了一个 delete [] str。
一分钟后 内存消耗 还是 937 KB
对比可以看到,用死循环来判断内存是否泄露还是一个比较可靠的方法的,如果有泄露,一会内存就消耗没了。
上面会泄露内存的 一会就消耗了几个G,而下面的那个不泄露内存的一直也就几百KB。