Delphi内存管理与内存泄漏探析
1引 言
Delphi是Borland公司的划时代之作,以其功能强大且易学好用而受到广大程序员的青睐。关于Delphi的文章很多,大多数是讨论其生产的高效率、各种应用的快速实现,却忽视了一个基本却非常重要的问题内存动态分配与安全释放。Delphi应用程序开发的许多问题是由不正确的内存分配或释放引起的,如内存未分配、未释放、未初始化、边界覆盖等。尤其是当自己编写一些组件程序时,稍不留心就会出现所谓“内存泄漏”的
问题:某些极端的情况下,当某一问题组件被重复调用时,会大量“吃掉”机器的内存,导致应用程序无法运行甚至死机的情况,从而严重影响了程序的运行稳定性。因此,内存安全管理是每一个程序员应具备的基本技能,也是高质量运行稳定的应用程序重要标志之一。开发一个运行稳定高质量的应用,就不可避免的遇到内存动态分配与释放的问题。本文主要就Delphi中内存分配与释放以及可能产生内存泄漏的原因展开讨论。
2动态内存分配与释放
Delphi环境下,动态分配内存的方式主要有2种:
第1种是使用Delphi标准库函数:AllocMem(GetMemor ReAllocMem,FreeMem)或New(Dispose)动态分配内存和释放内存;第2种是通过调用Win32 API函数LocalAlloc和LocalFree来实现。
2.1
Delphi标准库函数
其函数原型如下:
function AllocMem(Size:Cardinal):Pointer;
procedure GetMem(var P: Pointer;Size:Integer);
procedure ReAllocMem(var P:Pointer;Size:Integer);//重新分配内存
procedure FreeMem(var P:Pointer[;Size:Integer]);
procedure New(var P:Pointer);
procedure Dispose(var P:Pointer);
调用AllocMem是向系统请求指定大小的内存的一种方法。如果条件允许,操作系统就会进行指定大小内存的分配,返回值是一个指向内存块的指针。函数GetMem和ReAllocMem用法类似。区别是AllocMem函数在分配一个内存块的同时将每个字节初始化为0,而GetMem函数则不进行初始化为0的操作。而ReAllocMem函数则进行内存的重新分配操作。函数New自动给指针P分配SizeOf(P)大小的内存而不需要显式指定申请内存的大小。
调用函数AllocMem(GetMem,ReAllocMem)申用New分配的内存。
调用AllocMem(GetMem,ReAllocMem)及FreeMem的过程如下:
(1)首先要包含SysUtils单元文件
uses SysUtils
(2)在声名了相应类型的指针ptr:^Type后,调用AllocMem函数并指定所需大小的字节数作为参数。
(3)释放内存,调用FreeMem并将指针作为参数,最后将指针置空。
FreeMem(ptr);ptr:=nil;
另一对内存分配与释放的函
数New,Dispose用法与上面类似。
2.2Win32API函数LocalAlloc和LocalFree
函数原型如下:
Win32 APILocalAlloc和LocalFree函数只适用于Win32平台,其使用参阅在线Win32 sdk帮助文件。
无论使用哪一种方式向系统申请内存,在使用或释放申请的内存前,应首先测试一下指向内存块的指针是否有效。如果内存申请成功,函数返回的指针包含一有效地址(一个>0的长整数);否则,将返回一个空指针nil。因此可用if(Ptr=nil)测试指针是否有效。无论使用哪一种方式申请内存,必须使用相应的函数释放内存。
3内存泄漏原因分析
3.1申请的内存没有释放
这是一个基本的原因。似乎他是完全能够避免的。但是实际情况并非如此。尤其在编写一段比较庞大的程序时,在某个地方可能会申请一些系统资源,但是在某些情况下可能不需要申请这些资源,所以某些粗心的程序员忘记主动去释放他们。程序可能暂时不会出现异常,但是,如果这个函数被多次调用,特别是在一个长时间运行的服务程序当中,他就可能会耗尽系统的内