内存泄漏

title: 后果.
content: 内存泄漏会因为减少可用内存的数量从而降低计算机的性能。最终,在最糟糕的情况下,过多的可用内存被分配掉导致全部或部分设备停止正常工作,或者应用程序崩溃。  内存泄漏带来的后果可能是不严重的,有时甚至能够被常规的手段检测出来。在现代操作系统中,一个应用程序使用的常规内存在程序终止时被释放。这表示一个短暂运行的应用程序中的内存泄漏不会导致严重后果。  在以下情况,内存泄漏导致较严重的后果:
title: 简例.
content: 以下的例子无需任何程序设计的知识,但能表明如何导致内存泄漏及其造成的影响。请注意以下的例子是虚构的!  在此例中的应用程序是一个简单软件的一小部分,用来控制升降机的运作。此部分软件当乘客在升降机内按下一楼层的按钮时运行。  当按下按钮时:  此程序有一处会造成内存泄漏:如果在升降机所在楼层按下该层的按钮(即上述程序的第4步),程序将触发判断条件而结束运行,但内存仍一直被占用而没有被释放。这种情况发生得越多,泄漏的内存也越多。  这个小错误不会造成即时影响。因为人不会经常在升降机所在楼层按下同一层的按钮。而且在通常情况下,升降机应有足够的内存以应付上百次、上千次类似的情况。不过,升降机最后仍有可能消耗完所有内存。这可能需要数个月或是数年,所以在简单的测试下这个问题不会被发现。  而这个例子导致的后果会是不那么令人愉快。至少,升降机不会再理会前往其他楼层的要求。更严重的是,如果程序需要内存去开启升降机门,那可能有人被困升降机内,因为升降机没有足够的内存去开启升降机门。  内存泄漏只会在程序运行的时间内持续。例如:关闭升降机的电源时,程序终止运行。当电源再度开启,程序会再次运行而内存会重置,而这种缓慢的泄漏则会从头开始再次发生。
title: 程序设计问题.
content: 内存泄漏是程序设计中一项常见错误,特别是使用没有内置自动垃圾回收的程序语言,如C及C++。一般情况下,内存泄漏发生是因为不能存取动态分配的内存。目前有相当数量的调试工具用于检测不能存取的内存,从而可以防止内存泄漏问题,如IBM Rational Purify、BoundsChecker、Valgrind、Insure++及memwatch都是为C/C++程序设计亦较受欢迎的内存除错工具。垃圾回收则可以应用到任何程序语言,而C/C++也有此类函式库。  提供自动内存管理的编程语言如Java、C#、VB.NET以及LISP,都不能避免内存泄漏。例如,程序会把项目加入至列表,但在完成时没有移除,如同人把物件丢到一堆物品中或放到抽屉内,但后来忘记取走这件物品一样。内存管理器不能判断项目是否将再被存取,除非程序作出一些指示表明不会再被存取。  虽然内存管理器可以回复不能存取的内存,但它不可以释放可存取的内存因为仍有可能需要使用。现代的内存管理器因此为程序设计员提供技术来标示内存的可用性,以不同级别的「存取性」表示。内存管理器不会把需要存取可能较高的对象释放。当对象直接和一个强引用相关或者间接和一组强引用相关表示该对象存取性较强。(强引用相对于弱引用,是防止对象被回收的一个引用。)要防止此类内存泄漏,开发者必须使用对象后清理引用,一般都是在不再需要时将引用设成null,如果有可能,把维持强引用的事件侦听器全部注销。  一般来说,自动内存管理对开发者来讲比较方便,因为他们不需要实现释放的动作,或担心清理内存的顺序,而不用考虑对象是否依然被引用。对开发者来说,了解一个引用是否有必要保持比了解一个对象是否被引用要简单得多。但是,自动内存管理不能消除所有的内容泄漏。
title: 影响.
content: 如果一个程序存在内存泄漏并且它的内存使用量稳定增长,通常不会有很快的症状。每个物理系统都有一个较大的内存量,如果内存泄漏没有被中止(比如重启造成泄漏的程序)的话,它迟早会造成问题。  大多数的现代计算机操作系统都有存储在RAM芯片中主内存和存储在次级存储设备如硬盘中的虚拟内存,内存分配是动态的——每个进程根据要求获得相应的内存。存取活跃的页面文件被转移到主内存以提高存取速度;反之,存取不活跃的页面文件被转移到次级存储设备。当一个简单的进程消耗大量的内存时,它通常占用越来越多的主内存,使其他程序转到次级存储设备,使系统的运行效率大大降低。甚至在有内存泄漏的程序终止后,其他程序需要相当长的时间才能切换到主内存,恢复原来的运行效率。  当系统所有的内存全部耗完后(包括主内存和虚拟内存,在嵌入式系统中,仅有主内存),所有申请内存的操作将失败。这通常导致程序试图申请内存来终止自己,或造成分段内存访问错误(segmentation fault)。现在有一些专门为修复这种情况而设计的程序,常用的办法是预留一些内存。值得注意的是,第一个遭遇得不到内存问题的程序有时候并不是有内存泄漏的程序。  一些多任务操作系统有特殊的机制来处理内存耗尽得情况,如随机终止一个进程(可能会终止一些正常的进程),或终止耗用内存最大的进程(很有可能是引起内存泄漏的进程)。另一些操作系统则有内存分配限制,这样可以防止任何一个进程耗用完整个系统的内存。这种设计的缺点是有时候某些进程确实需要较大数量的内存时,如一些处理图像,视频和科学计算的进程,操作系统需要重新配置。  如内存泄漏发生在内核,表示操作系统自身发生了问题。那些没有完善的内存管理的计算机,如嵌入式系统,会因为一个长时间的内存泄漏而崩溃。  一些被公众访问的系统,如网络服务器或路由器很容易被黑客攻击,加入一段攻击代码,而产生内存泄漏。
title: 其他内存消耗.
content: 值得注意的是,内存用量持续增加不一定表明内存泄漏。一些应用程序会储存越来越多资料到内存中(如用作快取。如果快取太大引起问题,这可能是程序设计上的错误,但并非是内存泄漏因为资料仍被使用。另一方面,程序有可能申请不合理的大量内存,因为程序设计者假设内存总是足够运行特定的工作;例如,图像档案处理器会在开始时阅读图像档案的内容并把之储存至内存中,有时候由于图像档案太大,消耗的内存超过了可用的内存导致失败。  另一角度讲,内存泄漏是一种特殊的编程错误,如果没有源代码,根据征兆只能猜测可能有内存泄漏。在这种情况下,使用术语“内存消耗持续增加”可能更确切。
title: 例子.
title: C.
content: 下面是一个C语言的例子,在函数f()中申请了内存却没有释放,导致内存泄漏。当程序不停地重复调用这个有问题的函数f,申请内存函数malloc()最后会在程序没有更多可用内存可以申请时产生错误(函数输出为NULL)。但是,由于函数malloc()输出的结果没有加以出错处理,因此程序会不停地尝试申请内存,并且在系统有新的空闲内存时,被该程序占用。注意,malloc()返回NULL的原因不一定是因为前述的没有更多可用内存可以申请,也可能是逻辑地址空间耗尽,在Linux环境上测试的时候后者更容易发生。
title: C++.
content: 以下例子中,储存了整数123的内存空间不能被删除,因为地址丢失了。这些空间已无法再使用。

Summary: 内存泄漏(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

Fuite de mémoire: En informatique, une fuite de mémoire est un bogue expliqué par une occupation croissante et non contrôlée ou non désirée de la taille des données résidentes en mémoire, ce qui entraine la saturation de la mémoire de l’ordinateur.