内存问题的相关概念

内存泄漏:

分配的内存不足以放下数据项序列,称为内存溢出。一个盘子 用尽各种方法只能装4 个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。
以发生的方式来分类,内存泄漏可以分为4 类:

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

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

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

  4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结
    束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终
    程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几
    天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所
    有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
    从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为
    一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄
    漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次
    性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害
    性则非常大,因为较之于常发性和偶发性内存,泄漏它更难被检测到

====================================================

内存越界:

何谓内存访问越界,简单的说,你向系统申请了一块内存,在使用这块内存的时候,超出了你申请的范围。

内存越界使用,这样的错误引起的问题存在极大的不确定性,有时大,有时小,有时可能不会对程序的运行产生影响,正是这种不易重现的错误,才是最致命的,一旦出错破坏性极大。

什么原因会造成内存越界使用呢?有以下几种情况,可供参考:
例1:
char buf[32] = {0};
for(int i=0; i 32
{
buf[i] = 'x';
}
....
例2:
char buf[32] = {0};
string str = "this is a test sting !!!!";
sprintf(buf, "this is a test buf!string:%s", str.c_str()); //out of buffer space
....
例3:
string str = "this is a test string!!!!";
char buf[16] = {0};
strcpy(buf, str.c_str()); //out of buffer space

类似的还存在隐患的函数还有:strcat,vsprintf等
同样,memcpy, memset, memmove等一些内存操作函数在使用时也一定要注意。

当这样的代码一旦运行,错误就在所难免,会带来的后果也是不确定的,通常可能会造成如下后果:

1.破坏了堆中的内存分配信息数据,特别是动态分配的内存块的内存信息数据,因为操作系统在分配和释放内存块时需要访问该数据,一旦该数据被破坏,以下的几种情况都可能会出现。
*** glibc detected *** free(): invalid pointer:
*** glibc detected *** malloc(): memory corruption:
*** glibc detected *** double free or corruption (out): 0x00000000005c18a0 ***
*** glibc detected *** corrupted double-linked list: 0x00000000005ab150 ***

2.破坏了程序自己的其他对象的内存空间,这种破坏会影响程序执行的不正确性,当然也会诱发coredump,如破坏了指针数据。

3.破坏了空闲内存块,很幸运,这样不会产生什么问题,但谁知道什么时候不幸会降临呢?

通常,代码错误被激发也是偶然的,也就是说之前你的程序一直正常,可能由于你为类增加了两个成员变量,或者改变了某一部分代码,coredump就频繁发生,而你增加的代码绝不会有任何问题,这时你就应该考虑是否是某些内存被破坏了。

排查的原则,首先是保证能重现错误,根据错误估计可能的环节,逐步裁减代码,缩小排查空间。
检查所有的内存操作函数,检查内存越界的可能。常用的内存操作函数:

sprintf snprintf
vsprintf vsnprintf
strcpy strncpy strcat
memcpy memmove memset bcopy

如果有用到自己编写的动态库的情况,要确保动态库的编译与程序编译的环境一致。

你可能感兴趣的:(内存问题的相关概念)