页面

2009年4月24日

VB程序之优化内存篇

一、减少加载窗体数目
每一个加载的窗体,无论可视与否,都要占据一定数量的内存(其数量随窗体上控件的类型和数量,以及窗体上位图的大小等的不同而变化)。只在需要显示时才加载窗体,不再需要时,卸载窗体(而不是隐藏窗体)。记住,任何对窗体的属性、方法或控件的引用,或对用
New 声明的窗体变量的引用,都会导致 Visual Basic 加载该窗体。

当使用
Unload 方法卸载窗体时,只能释放部分窗体所占空间。要释放所有空间,可用关键字 Nothing 使窗体的引用无效:

Set
Form = Nothing

二、减少控件数目
当设计应用程序时,窗体应尽量少用控件。实际的限制取决于控件的类型和系统,但实际上,含有大量控件的窗体将运行缓慢。一项与之相关的技术是:设计时,尽可能地使用控件数组,而不是在窗体上放置大量同类型的控件。

详细信息
关于控件数组的详细信息,请参阅“使用 Visual Basic 的标准控件”中的“使用控件数组”。

三、用标签代替文本框
标签控件占用的
Windows 资源比文本框少,因此,在可能的情况下,应使用标签代替文本框。例如,当窗体上需要一个隐藏的控件保存文本时,使用标签更有效。

四、保持数据在磁盘文件或资源中,并且只在需要时才加载
在设计时,直接放入应用程序的数据(象属性或代码中的文字字符串和数值)将增加运行时应用程序占用的内存。运行时从磁盘文件或资源中加载数据可减少占用内存。这对大位图和字符串特别有价值。

详细信息
关于向应用程序添加资源的详细信息,请参阅“再论编程”中“利用资源文件进行工作”。

五、组织模块
Visual
Basic 只在需要时才加载模块—即当代码调用模块中的一个过程时,模块才被加载到内存。如果从未调用一特定模块中的过程,Visual Basic 决不加载该模块。因此,尽量把相关的过程放在同一模块中,让 Visual Basic 只在需要时才加载模块。

六、考虑替换
Variant 数据类型
Variant
数据类型使用极其灵活,但是比其它数据类型所占内存大。当要压缩应用程序多余的空间时,应考虑用其它数据类型替代 Variant 变量,特别是替代 Variant 变量数组。

每一个
Variant 占用 16 个字节,而 Integer 2 个字节,Double 8 个字节。变长字符串变量占用 4 个字节加上字符串中每一个字符占用 1 个字节,但是,每一个包含字符串的 Variant 都要占用 16 个字节加上字符串中每一个字符占用 1 个字节。因为它们太大,因此在用作局部变量或过程的参数时,Variant 变量是特别烦人的,这是因为它们消耗堆栈空间太快。

但在有些情况下,使用其它数据类型替代
Variant,灵活性降低了,为弥补损失的灵活性,不得不增加更多的代码。结果是大小没有真正的减小。

七、使用动态数组,并在删除时回收内存
使用动态数组代替固定数组。当不再需要动态数组的数据时,用
Erase ReDim Preserve 放弃不需要的数据,并回收数组所用内存。例如,用以下代码可回收动态数组所用空间:

Erase
MyArray

这里,Erase
完全删除数组,ReDim Preserve 则只缩短数组而不丢失其内容:

ReDim
Preserve MyArray(10, smallernum)

删除了固定大小数组,也不能回收该数组所占空间—只是简单地清除数组每一元素中的值。如果元素是字符串,或包含字符串或数组的
Variant 变量,那么删除数组可回收这些字符串或 Variants 所占内存,而不是数组本身所占内存。

八、回收被字符串或对象变量用过的空间
当过程结束时,可自动回收(非静态)局部字符串和数组变量所用空间。但是,全局和模块级的字符串和数组变量一直存活到整个程序结束。要想应用程序尽量小,就得尽可能回收这些变量所用空间。将零长度字符串赋给字符串变量,可回收其空间:

SomeStringVar
= "" '回收空间。

同样地,将对象变量设置成
Nothing 可回收该对象所用的部分(而不是全部)空间。例如,删除一个 Form 对象变量:

Global
F As New StatusForm

F.Show 1 'Form 加载并以模态显示。
X = F.Text1.Text '用户按下按钮
'隐藏窗体。
Unload F '删除窗体可视部分。
Set F = Nothing '回收空间(模块数据)。

即使没有使用显式窗体变量,也应注意将不再用的窗体卸载,而不是简单地隐藏。

九、消除死代码和无用的变量
在开发和修改应用程序时,可能遗留了死代码—
代码中的一个完整过程,而它并没有被任何地方调用。也可能声明了一些不用的变量。虽然,在创建 .exe 文件中,Visual Basic 确实可删除无用的常数,但不能删除无用的变量和死代码。注意要复查代码,查找并删除无用的变量和死代码。例如,Debug.Print 语句,在运行 .exe 时被忽略,可它常常出现在 .exe 文件中。

当创建
.exe 文件时,含有字符串和变量作为参数的 Debug.Print 语句不会被编译。但是,对于含有函数作为参数的 Debug.Print 语句,其本身被编译器忽略,而函数则被编译。因此,在应用程序运行时,函数被调用,但返回值被忽略。因为,在 .exe 文件中,函数作为 Debug.Print 的参数出现时,将占用空间和 CPU 周期时间,所以在生成 .exe 文件前,最好删除这些语句。

在“编辑”菜单中使用“查找”命令搜索特定变量的引用。或者,当每个模块都含有
Option Explicit 语句时,通过删除或注释该变量的声明,并运行应用程序,可迅速发现变量是否被使用。若该变量被使用,则 Visual Basic 将出错。若不出错,则该变量没被使用

释放数组内存

Dim ray() As Integer '动态数组。
ReDim ray(10) '分配存储空间。
Erase ray '释放数组所用内存。

从内存中卸载窗体或控件
语法
Unload object
object 所在处是要卸载的 Form 对象或控件数组元素的名称。
说明
当所占内存另有它用,或需要重新设置窗体、控件的属性为初始值时,就有必要卸载窗体或控件。
在卸载窗体前,会发生 Query_Unload 事件过程,然后是 Form_Unload 事件过程。在其中任一过程中设置 cancel 参数为 True 可防止窗体被卸载。若为 MDIForm 对象,先发生 MDIForm 对象的 Query_Unload 事件过程,接着是各 MDI 子窗体 Query_Unload 事件过程和 Form_Unload 事件过程,最后是 MDIForm 对象的 Form_Unload 事件过程。
当窗体卸载之后,所有在运行时放到该窗体上的控件都不再是可访问的。在设计时放到该窗体上的控件将保持不变;但是,当窗体重新加载时,在运行时对这些控件及其属性的任何更改将丢失。所有对于窗体属性的更改也将丢失。对窗体上任何控件的访问会导致窗体重新加载。
注意 在卸载窗体时,只有显示的部件被卸载。和该窗体模块相关联的代码还保持在内存中。
只有在运行时添加到窗体上的控件数组元素才能用 Unload 语句卸载。重新加载被卸载的控件时,其属性会被重新初始化。

没有评论: