存资源,甚至导致主机系统瘫痪。所以有个基本原则就是你一定要释放你所创建的对象,让Delphi组件去释放他们所创建的任何东西。
3.2对同一个对象创建了多个实例,但只释放了某一个实例
我们来看一个例子:在“智能型远程作业
系统”中,学生答题表单AnsFrm:TAnsFrm有一个按钮BtnFrmu,点击此按钮调用“公式编辑器”FrmuEdit:TFrmuEdit,由于程序需要,当“公式编辑器”界面被关闭时,并不释放其实例,直到关闭学生答题表单AnsFrm时再去释放这个实例。
TansFrm设置私有变量:FrmuEdit:TFrmuEdit。点击按钮BtnFrmu事件代码:
现在n次点击按钮BtnFrmu,则将创建n个“公式编辑器”实例,然而关闭表单AnsFrm时实际上只释放了最后一个实例,还有(n-1)个实例在内存中,从而造成了内存泄漏。
解决方法是创建新的实例之前先检测是否存在某个实例,如果存在,则不创建。修改按钮BtnFrmu的OnClick事件为:
如果FrmuEdit已经被创建,则Assigned(FrmuEdit)返回真;反之,返回假。现在无论点击按钮BtnFrmu多少次,内存中只有TFrmuEdit的一个实例,从而有效地避免了此种内存泄漏的发生。
3.3用于释放资源的代码实际上并没有被调用
开发Delphi组件
程序时可能会出现这种情况。Delphi是事件驱动的,事件之间有着各种联系。组件程序开发者一定要十分清楚Delphi的事件机制,尤其要明白某些事件(消息)之间的先后调用关系。否则,如果你认为事件1一定会调用事件2,所以在事件2中编写了释放内存的代码;而事
实上事件2并不调用(或有时不调用)事件1,则这段释放内存的代码实际上并不起作用,当然要造成内存的泄漏。笔者在开发“智能型远程
作业系统”的“图形/文本混合编辑器”组件程序时就遇到此种情形。
“图形/文本混合编辑器”TEditEx=class(TCustomControl),采用多缓冲技术,TEditEx有私有成员:GraphDC,TextDC,BuffDC:HDC(图形缓冲,文本缓冲和混合缓冲设备环境句柄);设备环境初始化:
注意到TEditEx是从TCustomControl继承的,不是一个窗体类,故其实例被关闭时不会触发WM_CLOSE消息,即不调用这部分代码去释放申请的资源;也就是说在关闭这个实例后,向系统申请的这部分资源(约2 MB)仍然在内存中。学生在答题时会频繁的用到“图形/文本混合编辑器”,即频繁的创建TEditEx的一个实例,然后关闭他,但是却不释放所申请的资源。在使用“图形/文本混合编辑器”4~6次(和机器有关)后,系统资源接近枯竭而不得不关闭主程序甚至要重启机器。
解决方法就是在销毁器中释放这些资源:
3.4出现异常时没有释放内存
程序运行时难免发生异常,如果此处恰好存放了释放资源的代码,则申请的资源将得不到释放,从而产生一种内存泄漏。采用Delphi的异常处理技术,可以确保申请资源的安全释放。Delphi支持如下2种异常处理:try…except和try…finally。其语法分别是:
try statements except exceptionBlock end和trystatementList1 finally statementList2 end。
这2种异常处理是有区别的:当系统资源被分配后,如果希望仅当在出现程序异常时释放资源,一般应使用try…except;如果不管程序在执行程序块时是否出现异常均希望释放资源,一般使用try…finally。切忌滥用异常处理结构,否则,将人为地降低程序的性能。申请内存或新建内存对象以后,将可能产生异常的代码放在try部分,一旦异常发生,无论是try部分的哪一行产生的,程序均会跳转到异常处理代码段(except或finally部分),在这部分存放释放资源的代码,以保证申请资源的释放。正确使用Delphi提供异常处理技术,无论程序在运行时出现何种异常,都能保证申请资源的释放。
4结语
内存的动态分配与安全释放,对于应用的稳定、主机系统的安全非常重要。要对程序中各种对象(这里的对象是泛指那些占用系统资源的变量(包括各种基本类型变量和类实例对象变量等))的生存(包括从分配到释放)有完全清楚的认识,杜绝内存泄漏的发生,开发出健壮、高效的应用程序。