目录
内存泄漏
#问: 什么是内存泄漏?
内存泄漏:指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
一句话:
内存泄漏通常是因为我们的疏忽,或者是一些程序的错误,而导致不再使用的内存没有释放。
(错误如:抛出的异常所导致,new的空间并未进行delete)
void MemoryLeaks()
{
// 1.内存申请了忘记释放
int* p1 = (int*)malloc(sizeof(int));
int* p2 = new int;
// 2.异常安全问题
int* p3 = new int[10];
Func(); // 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.
delete[] p3;
}
#问: 内存泄漏是指针丢了还是内存丢了?
是指针丢了,因为如果指针没有丢就不存在内存泄漏。,因为只要指针没有丢我们就还可以进行释放。
内存会丢?是并不会的!内存都在进程地址空间的位置,Linux下进程地址空间还会根据页表结构然后与物理内存进行映射。它是一直都在那个位置,只是因为它的指针被我们所搞丢了,从而导致我们不用了,但是想释放都释放不了。于是系统以为我们在使用,而我们没有在使用,并且一直不会使用,于是内存泄漏,可用内存越来越少。
内存还在,进程正常结束,内存也会释放。
#问: 内存泄漏有什么危害?
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
- 僵尸进程:
僵尸进程有内存泄漏,因为是僵尸进程,所以进程没有正常的释放,正常的结束,于是资源没有的得到释放。僵死进程的内核栈无法被释放掉(1K 或者 2K大小),因为在栈的最低端,有着thread_info结构,它包含着 struct_task 结构,这里面包含着一些退出信息。这个时候僵尸进程非常的多,系统就会越来越慢。
- 长期运行:
虽然进程结束,内存泄漏就会释放,但是有一些进程是会长期运行的。最怕的就是一次只会泄漏一点点,这样的泄漏在长期的运行下就会凸显出来。
内存泄漏分类
C/C++程序中一般我们关心两种方面的内存泄漏:
- 堆内存泄漏(Heap leak)
堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
- 系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
如何检测内存泄漏
其他工具:内存泄漏工具比较
如何避免内存泄漏
- 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。
ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。
- 采用RAII思想或者智能指针来管理资源。
- 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
ps:检测工具的内部实现原理,申请内存用一个容器记录下来,释放内存时从容器中删除掉。程序结束前,或者没有任何任务时,容器中的资源可能就是内存泄漏的。
- 出问题了使用内存泄漏工具检测。
ps:不过很多工具都不够靠谱,或者收费昂贵。
总结:内存泄漏非常常见,解决方案分为两种:
- 事前预防型,如:智能指针等。(打疫苗)
- 事后查错型,如:泄漏检测工具。(做核酸)