什么是内存泄漏?

时间:2010-07-30 17:16:47

标签: memory-leaks

显然Wikipedia有关于该主题的大量信息,但我想确保理解。从我可以说的是,了解堆栈/堆关系以了解内存泄漏是很重要的?

所以这就是我(我想)的理解。更正是非常受欢迎的!

首次启动程序时,会分配一块内存,例如0x000到0xFFF。第一部分(比如0x000到0x011)是加载程序代码的代码/文本段。

+--------------+ 0x011
| Program Code |
+--------------+ 0x000

然后你有堆栈(比如0x012到0x7ff)保存局部变量,它们被存储/检索FIFO。所以,如果你有像

这样的东西
char middleLetter(string word){
     int len = word.length();
     return word[len/2];
}

int main(){
   int cool_number;
   char letter;
   letter = middleLetter("Words");
   ...

然后你的变量将在堆栈上分配,如下所示:

+-------------+ 0x7ff
|             |
|             |
|             |
| ...         |
| len         |
| letter      |
| cool_number |
+-------------+ 0x012

当然,如果你在某处(使用mallocnew)分配内存,但从不释放它,那么你的堆可能看起来像这样,你现在有内存泄漏:

+-------------+ 0xfff
|             |
| malloc(20)  | 0xf64
| malloc(50)  | 0xf32
| malloc(50)  | 0xf00
| ...         |
|             |
+-------------+ 0x800

这意味着虽然您可以使用指针算法直接访问0xf32,但操作系统/您的程序认为已经占用了内存位置0xf00-0xf46,并且不会再使用这些位置进行存储,直到您的程序为止关闭,释放内存。但共享内存怎么样?维基百科说它不会被发布(直到你的计算机重新启动?)。你怎么知道它是否是共享内存?

这是一个非常好的基本理解吗?有什么我错过/有错吗?谢谢你的期待!

7 个答案:

答案 0 :(得分:7)

似乎你理解它 - 有一个例外:在你的例子中,len是一个堆栈变量,就像其他一切一样。 newmalloc在堆上创建,其他所有内容(本地变量等)都在堆栈上。主要的局部变量与任何其他函数的变量没有区别。

共享内存是一种相当罕见的情况,你通常不需要它,因此你不会拥有它,除非你明确要求它(否则,一些随机的其他进程可能会使用你的进程使用的相同内存 - 显然,这会破坏事情。)

答案 1 :(得分:5)

您的函数变量通常也在堆栈中,而不是堆。在大多数系统中,堆用于动态分配。通常的内存泄漏情况是

  1. 调用一些功能F
  2. F分配(new或malloc)一些内存
  3. F返回来电者(无删除/免费)
  4. 指向动态分配的内存的指针超出范围
    • 仍然分配了内存。
    • 您无法再删除/释放

答案 2 :(得分:4)

这样想。在使用需要编码器管理内存的语言进行开发时,您需要为程序将使用的每个对象显式分配和销毁内存。很容易知道什么时候你没有正确创建,因为你的程序将无法正常工作。查找和调试未正确销毁对象的情况(这称为内存泄漏)会更加困难。

让我们来看一个典型的应用,让我们说一个RSS新闻阅读器。在像这样的应用程序中,通常有许多循环(循环遍历不同的RSS提要,不同的RSS项目,RSS标签等)。如果您有一个实例,其中创建的对象未被正确销毁(或释放),则每次运行“泄漏”代码时,您将在内存中找到另一个被遗弃的对象。如果循环运行1,000次,则会有1,000个被抛弃的对象占用空间。您可以看到它如何快速累积以消耗宝贵的资源。

答案 3 :(得分:4)

内存泄漏变得简单:无论何时使用malloc / new分配内存,并且在完成使用该内存后不使用free / delete解除分配...将导致内存泄漏!分配的内存将保留在那里,程序将不再使用该空间。

当泄漏在多次调用的函数上时,这是一个严重的问题,每次调用函数时泄漏都会变得越来越大。

答案 4 :(得分:3)

通常,函数(子程序)中的自动变量也将存储在堆栈中。只有'malloc'或'new'数据分配来自堆。接下来,可以在程序结束之前释放并重复使用基于堆的分配(多次)。分配系统跟踪使用中区域和释放区域。最后,内存泄漏是指程序在没有释放的情况下丢失了一些已分配的内存。这可以通过在具有新值的指针上写入,或者将指针存储在具有有限生命期/范围的变量中来实现。

答案 5 :(得分:3)

看起来你正在使用C ++代码。在C ++中,局部变量被放在堆栈上(我猜测全局变量也是如此,但我不确定)。所以你的middleLetter函数中的len也会被置于调用堆栈中。我建议您阅读这篇文章:http://en.wikipedia.org/wiki/Call_stack

当您使用类型为int *x = new int;的new运算符时,会发现足够的连续内存放置int。用于引用它的指针* x虽然是局部变量。如果x超出范围而您丢失指针,则不会释放堆上的内存。即使您现在无法引用它,该程序仍然会“使用”该内存。因为你不能引用它,所以你不能解除它(或删除它)。

当你继续这样做时,你最终会耗尽你可以分配给它的堆空间,并且你的程序会越来越接近爆炸,因为它没有内存可以处理其他问题。

答案 6 :(得分:0)

在垃圾收集系统中,“内存泄漏”一词有时看起来有点模糊。我将提供以下定义,这与使用显式释放的垃圾收集系统一样适用: 如果存在输入S的初始序列和输入P的重复模式,则程序或子程序P具有存储器泄漏,使得:

  1. 输入程序或子程序输入S后跟P将使程序处于与P之前相同的“有意义”状态,但是
  2. 对于任何数量的内存Q,存在一定数量N的重复,使得馈送程序输入S后接N次重复P将导致程序使用多于Q的内存。

如果所有输入实际上都有助于程序的状态,那么没有内存泄漏的程序可能具有与输入大小无关的内存使用。例如,读入输入文件并以相反顺序写出的程序将需要足够的内存来保存文件。另一方面,具有内存泄漏的程序将需要无限量的内存来处理无限输入流,即使所需的内存量应该是有限的。

相关问题