Delphi内存管理与内存泄漏探析(转)

Delphi内存管理与内存泄漏探析

杨继宏,龚 晖,李 治

   :综述了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.2 Win32API函数LocalAlloc和LocalFree
  函数原型如下:

Win32 APILocalAlloc和LocalFree函数只适用于Win32平台,其使用参阅在线Win32 sdk帮助文件。
无论使用哪一种方式向系统申请内存,在使用或释放申请的内存前,应首先测试一下指向内存块的指针是否有效。如果内存申请成功,函数返回的指针包含一有 效地址(一个>0的长整数);否则,将返回一个空指针nil。因此可用if(Ptr=nil)测试指针是否有效。无论使用哪一种方式申请内存,必须使用相 应的函数释放内存。
3 内存泄漏原因分析
3.1 申请的内存没有释放
  这是一个基本的原因。似乎他是完全能够避免的。但是实际情况并非如此。尤其在编写一段比较庞大的程序时,在某个地方可能会申请一些 系统资源,但是在某些情况下可能不需要申请这些资源,所以某些粗心的程序员忘记主动去释放他们。程序可能暂时不会出现异常,但是,如果这个函数被多次调 用,特别是在一个长时间运行的服务程序当中,他就可能会耗尽系统的内存资源,甚至导致主机系统瘫痪。所以有个基本原则就是你一定要释放你所创建的对象,让 Delphi组件去释放他们所创建的任何东西。
3.2 对同一个对象创建了多个实例,但只释放了某一个实例
  我们来看一个例子:在“智能型远程作业系统”中,学生答题表单AnsFrm:TAnsFrm有一个按钮BtnFrmu,点击此按钮 调用“公式编辑器”FrmuEdit:TFrmuEdit,由于程序需要,当“公式编辑器”界面被关闭时,并不释放其实例,直到关闭学生答题表单 AnsFrm时再去释放这个实例。
    TansFrm设置私有变量:FrmuEdit:TFrmuEdit。点击按钮BtnFrmu事件代码:

posted @ 2009-07-27 12:59  Handll  阅读(3855)  评论(0编辑  收藏  举报