【转载】内存泄露和内存溢出

原文链接:内存泄露和内存溢出 – CSDN

作者:Overboom

补充:内存溢出的概念

​ 简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提供的内存,导致无法申请到足够的内存,于是就发生了内存溢出

​ 内存溢出 Out of Memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现Out of Memory

补充:内存泄露的概念

​ 内存泄漏指程序运行过程中分配内存给临时变量,用完之后却没有被GC回收,始终占用着内存,既不能被使用也不能分配给其他程序,于是就发生了内存泄漏

​ 内存泄露Memory Leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

Memory Leak会最终会导致Out of Memory

​ 内存泄露是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间的浪费称为内存泄露。内存泄露有时不严重且不易察觉,这样开发者就不知道存在内存泄露,但有时也会很严重,会提示你Out of Memory

一、内存泄露的概念

​ 内存泄漏Memory Leak是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。(摘抄自百度百科)

​ 内存泄露是由于疏忽或者错误造成程序未能释放已经不再使用的内存。内存泄露并非值内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成内存的浪费。(摘抄自wiki)

二、内存泄露的后果

​ 内存泄漏通常不会直接产生可观察的错误症状,而是逐渐积累,降低系统整体性能,极端的情况下可能使系统崩溃。

​ 内存泄漏会因为减少可用内存的数量从而降低计算机的性能。最终,在最糟糕的情况下,过多的可用内存被分配掉导致全部或部分设备停止正常工作,或者应用程序崩溃。

​ 内存泄漏带来的后果可能是不严重的,有时甚至能够被常规的手段检测出来。在现代操作系统中,一个应用程序使用的常规内存在程序终止时被释放。这表示一个短暂运行的应用程序中的内存泄漏不会导致严重后果。

​ 在以下情况,内存泄漏导致较严重的后果:

  • 程序运行后置之不理,并且随着时间的流逝消耗越来越多的内存(比如服务器上的后台任务,尤其是嵌入式系统中的后台任务,这些任务可能被运行后很多年内都置之不理);
  • 新的内存被频繁地分配,比如当显示电脑游戏或动画视频画面时;
  • 程序能够请求即使在程序终止之后也不会被释放的内存(比如共享内存);
  • 泄漏在操作系统内部发生;
  • 泄漏在系统关键驱动中发生;
  • 内存非常有限,比如在嵌入式系统或便携设备中;
  • 当运行于一个程序终止时内存并不自动释放内存的操作系统(比如AmigaOS)之上时。

三、C语言内存泄露示例

1.指针重新赋值

#include <stdio.h>

int main(void)
{
    char *p =  (char *)malloc(10);
    char *np = (char *)malloc(10);

    p = np;
    free(p);
    free(np);
    return 0;

}

​ p 和 np 分别被分配了 10 个字节的内存,它们各自的内存如图 1 所示。

​ 当执行p = np之后,这时候,指针变量 p 被 np 指针重新赋值,其结果是 p 以前所指向的内存位置变成了孤立的内存,如图 2 所示。它无法释放,因为没有指向该位置的引用,从而导致 10 字节的内存泄漏。

​ 因此,在对指针赋值前,一定确保内存位置不会失去控制。

2.错误的内存释放

3.返回值不正确的处理

​ 有时候,某些函数会返回对动态分配的内存的引用,如下面的示例代码所示:

char *f()
{
    return (char *)malloc(10);
}
void f1()
{
    f();
}

​ 很明显,函数 f1 中对 f 函数的调用并未处理该内存位置的返回地址,其结果将导致 f 函数所分配的 10 个字节的块丢失,并导致内存泄漏。

4.在内存分配后忘记使用free进行释放

​ 最后,要避免这些内存相关的问题导致的内存越界与内存遗漏等错误,可以参考如下几点进行:

  • 确保没有在访问空指针。
  • 每个内存分配函数都应该有一个 free 函数与之对应,alloca 函数除外。
  • 每次分配内存之后都应该及时进行初始化,可以结合 memset 函数进行初始化,calloc 函数除外。
  • 每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。
  • 在对指针赋值前,一定要确保没有内存位置会变为孤立的。
  • 每当释放结构化的元素(而该元素又包含指向动态分配的内存位置的指针)时,都应先遍历子内存位置并从那里开始释放,然后再遍历回父节点。
  • 始终正确处理返回动态分配的内存引用的函数返回值。

————————————————
版权声明:本文为CSDN博主「Overboom」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:

如有侵权,请联系我删除

Email:[email protected]


   转载规则


《【转载】内存泄露和内存溢出》 Overboom 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录