内存溢出和内存泄漏以及常用解决方案

什么是内存泄漏?

内存泄漏(存储渗漏)是用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元,直到程序结束。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。

1.内存泄漏形象的比喻是“操作系统可提供给所有进程的存储空间正在被某个进程榨干”,最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以“内存泄漏”是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区的设定的大小由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。
2. 一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。
3. 应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。
4. 内存泄漏和对象的引用计数有很大的关系,再加上c/c++都没有自动的垃圾回收机制,如果没有手动释放内存,问题就会出现。如果要避免这个问题,还是要从代码上入手,良好的编码习惯和规范,是避免错误的不二法门。

内存泄漏以发生的方式可以分为4类:

常发性

发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。

偶发性

发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。

一次性

发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。

隐式

程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天、几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

什么是内存溢出?

内存溢出(Out Of Memory,简称 OOM)是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于能提供的最大内存。此时程序就运行不了,系统会提示内存溢出。

内存溢出错误会导致处理数据的任务失败,甚至会引发平台崩溃等严重后果。
对于内存溢出大部分的处理方法是重新执行任务,然而, 对于由系统配置、数据流、用户代码等原因而导致的内存溢出错误,即使用户重新执行任务依然无法避免。

内存溢出与内存泄漏的关系

内存泄露是造成内存溢出的其中一个原因,但是内存泄露不一定会造成内存溢出。简单来说,内存溢出就是占用内存太大,超过了系统可以承受的范围;而内存泄露则是由于对程序运行分配的对象回收不及时甚至于脆没有被回收,久而久之,则在系统分配的堆空间里面产生了很多无用的引用。

从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。

内存溢出的原因

1、内存中加载的数据量过于庞大,如一次从数据库取出过多数据。

2、内存泄漏。

3、代码中存在死循环或循环产生过多重复的对象实体。

4、使用的第三方软件中的BUG。

5、启动参数内存值设定的过小。

内存溢出解决方案

方案1:

检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。通过仔细查看日志,分析内存溢出前做过哪些操作,可以大致定位有问题的模块。

方案2:

对代码进行走查和分析,找出可能发生内存溢出的位置。重点排查以下几点:

  1. 检查代码中是否有死循环或递归调用。大量的递归调用会建立函数的副本,会耗费大量的时间和内存。
  2. 检查是否有大循环重复产生新对象实体。
  3. 检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在软件运行初期,数据库中数据较少,不容易出问题,随着运行时间的增长,数据库中数据量也随之增长,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
  4. 检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

方案3:

使用内存查看工具动态查看内存使用情况。对于缓慢的内存泄漏,软件运行初期可能一些正常,但由于在运行过程中一直在申请内存并不释放,导致系统资源耗尽从而引发软件崩溃等问题。这种缓慢的内存泄漏,用上面2个方案解决不了,这就需要使用内存查看工具实时监测内存的使用情况。

猜你喜欢

转载自blog.csdn.net/youarenotme/article/details/107894059