【翻译】了解和防止内存泄露

支持面向对象编程Delphi是如此丰富和强大。雷和对象允许模块化编程。除了更多的模块和更多复杂的组件外,同时也带了更多的迷惑和更多复杂的Bugs。

当用Delphi开发一个程序(几乎)总是那么的有趣,当你感觉整个世界都在反对你的这个局面下。

无论什么时候你需要创建一个对象你就得释放它所使用的内存。无疑此时try...finally...end语句块可以帮助你防止内存泄露;它会持续不断的监视你的代码的安全性。

当程序失去释放它所耗费的内存的能力的时候就会发生内存(或资源)泄露。重复的内存泄露会导致一个进程无限制的使用内存。内存泄露是一个严重的问题--如你有个运行一周7天24小时的程序里一段代码引起内存泄露,那么程序将吃光所有可用的内存,最后会使机器停止反应。

Delphi的内存泄露
首先要阻止内存泄露就必须了解它们是如何出现的。下列所述将讨论一些常见的误区以及写没有内存泄露的Delphi代码的练习。

大多是情况下,(简单的)Delphi程序,你使用组件(Buttons, Memos, Edits等)拖放到一个窗体上(在设计期),不用太多的担心内存管理。一旦组件被拖放到窗体上,那么窗体就会成为它的所有者并且当窗体关闭(销毁)时将释放该组件的内存。窗体,作为一个拥有者,会为组件所拥有的内存负责。简单地说:窗体上的组件会自动创建和销毁。

一个简单的内存泄露示例
不论如何,在任何一个不繁琐的Delphi程序里,你需要实例化Delphi组件在运行期。你会实例化一些你自己编写的类。比如说你有一个类TDeveloper,它有一个方法DoProgram。现在,当要使用TDeveloper类时,你会通过调用Create方法(构造器)来实例化它。Create方法会给这个新对象分配内存并且返回这个对象的引用。

var
  zarko: TDeveloper
begin
  zarko := TMyObject.Create;
  zarko.DoProgram;
end;

这儿就有一个简单的内存泄露

不论什么时候你创建一个对象,你就必须释放它所占用的内存。要释放分配给一个对象的内存,你就必须调用Free方法,非常肯定地说,你也会用try...finally...end语句块。

var
  zarko : TDeveloper
begin
  zarko := TMyObject.Create;
  try
    zarko.DoProgram;
  finally
    zarko.Free;
  end;
end;

这是一个安全分配内存和重新分配的代码。

注意:如果你想动态实例化一个Delphi组件并且是在使用完后释放,总是传递nil作为拥有者。不这样做会带来不必要的风险,也会给性能和代码维护带来麻烦。请继续阅读本文。

一个简单的资源泄露示例
与使用Create和Free方法来创建和释放对象相比,你也必须非常小心的使用“外部”(文件,数据库等)。

比如说你需要操作一些文本文件。一个非常简单的做法:AssignFile方法是一个文件变量关联一个磁盘上的文件,当你使用完该文件之后,你必须调用CloseFile函数释放掉之前使用的文件句柄。这只是你没明确的调用“Free”。

var
  F: TextFile;
  S: string;
begin
  AssignFile(F, 'c:\somefile.txt') ;
  try
    Readln(F, S) ;
  finally
    CloseFile(F) ;
  end;
end;

另外一个例子在你的代码里加载外部的DLLs,无论如何你用LoadLibrary,就必须调用FreeLibrary。

var
  dllHandle : THandle;
begin
  dllHandle := Loadlibrary('MyLibrary.DLL');
  //do something with this DLL
  if dllHandle <> 0 then
    FreeLibrary(dllHandle);
end;

.NET中的内存泄露?
尽管Delphi for .NET中的garbage collector(GC)管理着大部分的内存任务,但是内存泄露在.NET程序中也是不无可能的。这里有一篇文章在讨论Delphi for .NET中的GC。(译者注:文章地址:http://delphi.about.com/od/delphifornet/a/aa060104a.htm)

如何抵抗内存泄露:
除了编写安全的内存代码模块外,防止内存泄露可以使用一些有效的第三方工具。Delphi内存泄漏的修复工具可以帮助你捕捉程序错误比如内存污染、内存泄露、内存分配错误、变量初始化错误、变量定义冲突、指针错误等等。

最后,自从我与Murphy一起开始,我会以同样的思维完成:

如果有人抱怨你的程序有一个内存泄露的问题,简单的回答他:

“这不是Bug, 只是文档中没有提到这个功能” :))

原文地址:http://delphi.about.com/od/oopindelphi/a/memoryleak.htm


评论: 0 | 引用: 0 | 查看次数: -
发表评论
昵 称:
密 码: 游客发言不需要密码.
邮 箱: 邮件地址支持Gravatar头像,邮箱地址不会公开.
网 址: 输入网址便于回访.
内 容:
验证码:
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 开启 | [img]标签 关闭