内存溢出
内存溢出(out of memory),是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory错误;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
而内存溢出的一大原因就是因为内存泄露。
内存泄露
内存泄露(memory leak),是指程序在申请内存后,无法释放已申请的内存空间。
内存泄露我们通常关注两类情况:
- 堆内存泄漏 (Heap leak):堆内存指的是程序运行中根据需要通过malloc,realloc new等从堆中分配的一块内存,再是完成后必须通过调用对应的 free或者delete删掉。如果程序的设计的错误导致这部分内存没有被释放,那么此后这块内存将不会被使用,就会产生Heap Leak.。
- 系统资源泄露(Resource Leak):主要指程序使用系统分配的资源比如 Bitmap,handle,SOCKET等没有使用相应的函数释放掉,导致系统资源的浪费,严重可导致系统效能降低,系统运行不稳定。
内存泄露的场景
- malloc/free或者new/delete未成对出现 通过局部分配的内存
- 未在调用者函数体内释放
- 没有将基类的析构函数定义为虚函数,当基类的指针指向子类时,delete该对象时,不会调用子类的析构函数 没有正确地清除嵌套的对象指针
- 由于程序运行时出现不可遇见的错误,导致内存泄漏
内存泄露的检测方法
-
手动检测
为了避免内存泄露,在开发时采用良好的一致的编程规范。在代码完成时可以手动检测代码是否出现可能发生内存泄露的典型场景,是否符合编码规范。 -
静态代码分析工具
使用静态代码分析工具,比如 splint, PC-LINT, BEAM 等对代码进行分析。 -
动态运行检测
使用实时检测工具,如 valgrind, Rational purify 等对代码进行分析。
如何避免内存泄露
- 使用智能指针
- 遵循合理可靠的编码规范
- 尽量少用静态变量
- 使用Arena
Arena是一种统一化管理内存生命周期的方法。所有需要在堆上分配的内存,不通过 malloc/new,而是通过 Arena 的 CreateObject 接口。同时,不需要手动的执行 free/delete,而是在 Arena 被销毁的时候,统一释放所有通过 Arena 对象申请的内存。所以,只需要确保 Arena 对象一定被销毁就可以了,而不用再关心其他对象是否有漏掉的 free/delete。
使用协程
内存泄露和内存溢出的关系
- 相同点:都会导致应用程序运行出现问题,性能下降或挂起。
- 不同点:内存泄露是导致内存溢出的原因之一,内存泄露积累起来将导致内存溢出;内存泄露可以通过完善代码来避免,内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。