什么是内存泄漏?
显然维基百科有关这个话题的大量信息,但我想确保我明白。 从我能告诉重要的是要理解堆栈/堆关系,以真正理解内存泄漏?
所以这就是我所理解的。 更正非常欢迎!
当你第一次启动你的程序时,会分配一块内存,比如0x000到0xFFF。 第一部分(比如0x000到0x011)是加载程序代码的代码/文本段。
+--------------+ 0x011 | Program Code | +--------------+ 0x000
然后你有堆栈(比如0x012到0x7ff),它包含局部variables,并且它们被存储/检索FIFO。 所以如果你有类似的东西
char middleLetter(string word){ int len = word.length(); return word[len/2]; } int main(){ int cool_number; char letter; letter = middleLetter("Words"); ...
然后你的variables将被分配在堆栈上,看起来像这样:
+-------------+ 0x7ff | | | | | | | ... | | len | | letter | | cool_number | +-------------+ 0x012
当然,如果你在某个地方(使用malloc
或new
)分配内存,但是从来没有释放它,那么你的堆可能看起来像这样,而你现在有一个内存泄漏:
+-------------+ 0xfff | | | malloc(20) | 0xf64 | malloc(50) | 0xf32 | malloc(50) | 0xf00 | ... | | | +-------------+ 0x800
这意味着你可以用指针算术直接访问0xf32,OS /你的程序认为已经占用了内存地址0xf00-0xf46,并且不会再使用这些地点来存储,直到你的程序closures,内存被释放。 但共享内存呢? 维基百科说,它永远不会被释放(直到你的电脑重新启动?)。 你怎么知道它是共享内存?
这是一个相当不错的基本理解? 有什么我失踪/有错吗? 感谢您的期待!
似乎你理解它 – 有一个例外:在你的例子中,len是一个像其他所有东西一样的栈variables。 new
或malloc
在堆上创build,一切(局部variables等)在堆栈上。 而且main的局部variables和其他函数的variables没有什么不同。
共享内存是一种非常罕见的情况,你通常不需要它,所以除非你明确地要求它,否则你将不会拥有它(否则,一些随机的其他进程可能会使用你的进程使用的相同的内存 – 显然,这会打破事情)。
你的函数variables通常也在堆栈中,而不是堆。 在大多数系统中,堆用于dynamic分配。 通常的内存泄漏情况是
- 调用一些函数F
- F分配(新的或malloc)一些内存
- F返回给调用者(不删除/免费)
- 指向dynamic分配的内存的指针超出了范围
- 内存仍然分配。
- 你不能删除/释放它
想想这样。 当用需要编码器pipe理内存的语言进行开发时,需要为程序将使用的每个对象显式分配和销毁内存。 当你不能正确地创build东西时,很容易知道,因为你的程序不能工作。 find并debugging不能正确销毁对象的情况(这被称为内存泄漏)要困难得多。
让我们拿一个典型的应用程序,让一个RSS新闻阅读器。 在这样的应用程序中,通常会有很多循环(循环不同的RSS提要,不同的RSS项目,RSS标签等等)。 如果你有一个创build的对象没有被正确销毁(或释放)的实例,那么每次运行“泄露”代码时,都会在内存中结束另一个被抛弃的对象。 如果循环运行1000次,则会有1000个废弃物体占用空间。 你可以看到如何快速加起来消耗宝贵的资源。
内存泄漏变得很简单 :只要你用malloc / new分配内存,并且在完成使用内存之后不用释放/删除内存释放…会导致内存泄漏! 分配的内存将保留在那里,并且该空间不会再被您的程序使用。
当泄漏发生在多次被调用的函数上时,这是一个严重的问题,每次函数被调用时泄漏越来越大。
通常,函数(子例程)中的自动variables也将被存储在堆栈中。 只有'malloc'或'new'数据分配来自堆。 接下来,在程序结束之前,基于堆的分配可以被释放并重用(很多次)。 分配系统跟踪使用区域和释放区域。 最后,内存泄漏是当你的程序丢失了一些分配的内存而没有释放它的时候。 这可以通过使用新值写入指针或将指针存储在具有有限生命期/范围的variables中来实现。
看起来你正在使用C ++代码。 在C ++本地variables放在堆栈(我猜全球也是,但我不知道)。 所以在你的middleLetter函数中len也会被放在调用堆栈中。 我build议阅读这篇文章: http : //en.wikipedia.org/wiki/Call_stack
当你使用新的运算符types,如int *x = new int;
例如,find足够的连续内存来放置一个int。 尽pipe你用来引用它的指针* x是一个局部variables。 如果x超出范围,并且丢失了指针,那么不会释放堆中的内存。 即使您现在没有办法引用它,该内存仍然被您的程序“使用”。 因为你不能引用它,你不能释放它(或删除它)。
当你继续这样做的时候,你最终会在堆中分配空间不足,而你的程序将会越来越近,因为它没有任何内存来处理其他问题。
在垃圾收集系统中,“内存泄漏”一词有时似乎有点模糊。 我将提供以下定义,这与垃圾收集系统一样适用于那些使用显式释放的系统:如果存在inputS的初始序列并重复inputP的模式,则程序或子程序P具有内存泄漏,这样:
- 进给程序或子程序inputS后跟P将使程序处于与P之前相同的“有意义”状态,但
- 对于任意数量的存储器Q,都存在一些重复次数N,从而给程序inputS进行N次重复的P将导致程序使用超过数量Q的存储器。
如果所有的input实际上都是对程序状态的贡献,那么没有内存泄漏的程序就可能具有与input大小无关的内存使用。 例如,读取input文件并以相反顺序写出的程序将需要足够的内存来保存文件。 另一方面,具有内存泄漏的程序将需要无限量的内存来处理无限的inputstream,即使所需的内存量应该是有限的。