一、减少加载窗体数目 每一个加载的窗体,无论可视与否,都要占据一定
数量的内存(其
数量随窗体上控件的类型和
数量,以及窗体上位图的大小等的不同而变化)。只在需要
显示时才加载窗体,不再需要时,卸载窗体(而不是隐藏窗体)。记住,任何对窗体的
属性、
方法或控件的引用,或对用 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 语句卸载。重新加载被卸载的控件时,其
属性会被重新初始化。 (二) 什么是一个高效的软件?一个高效的软件不仅应该比实现同样
功能的软件运行得更快,还应该消耗更少的系统资源。这篇
文章汇集了作者在使用VB进行软件开发时积累下来的一些经验,通过一些简单的例子来向你展示如何写出高效的VB
代码。其中包含了一些可能对VB程序员非常有帮助的技术。在开始之前,先让我陈清几个概念。 让
代码一次成型:在我接触到的程序员中,有很多人喜欢先根据
功能需求把
代码写出来,然后在此基础上优化
代码。最后发现为了达到优化的目的,他们不得不把
代码再重新写一遍。所以我建议你在编写
代码之前就需要考虑优化问题。 把握好优化的结果和需要花费的工作之间的关系:通常当完成了一段
代码,你需要检查和
修改它。在检查
代码的过程中,也许你会发现某些循环中的
代码效率还可以得到进一步的改进。在这种情况下,很多追求完美的程序员也许会立马
修改代码。我的建议是,如果
修改这段
代码会使程序的运行时间缩短一秒,你可以
修改它。如果只能带来10毫秒的
性能改进,则不做任何改动。这是因为重写一段
代码必定会引入新的
错误,而调试新的
代码必定会花掉你一定的时间。程序员应该在软件
性能和开发软件需要的工作量之间找一个平衡点,而且10毫秒对于
用户来说也是一个不能体会到的差异。 在需要使用面向对象
方法的时候尽量使用它;VB提供的机制不完全
支持面向对象的设计和编码,但是VB提供了简单的类。大多数人认为使用对象将导致
代码的效率降低。对于这一点我个人有些不同的意见;考察
代码的效率不能纯粹从运行速度的角度出发,软件占用的资源也是需要考虑的因素之一。使用类可以帮助你在整体上提升软件的
性能,这一点我会在后面的例子中详细说明。 如何提高
代码的运行速度 1. 使用整数(Integer)和长整数(Long) 提高
代码运行速度最简单的
方法莫过于使用正确的数据类型了。也许你不相信,但是正确地选择数据类型可以大幅度提升
代码的
性能。在大多数情况下,程序员可以将Single,Double和Currency类型的变量替换为Integer或Long类型的变量,因为VB处理Integer和Long的能力远远高于处理其它几种数据类型。 在大多数情况下,程序员选择使用Single或Double的原因是因为它们能够保存小数。但是小数也可以保存在Integer类型的变量中。例如程序中约定有三位小数,那么只需要将保存在Integer变量中的数值除以1000就可以得到结果。根据我的经验,使用Integer和Long替代 Single,Double和Currency后,
代码的运行速度可以提高将近10倍。 2. 避免使用变体 对于一个VB程序员来说,这是再明显不过的事情了。变体类型的变量需要16个字节的空间来保存数据,而一个整数(Integer)只需要2个字节。通常使用变体类型的目的是为了减少设计的工作量和
代码量,也有的程序员图个省事而使用它。但是如果一个软件经过了严格设计和按照规范编码的话,完全可以避免使用变体类型。 在这里顺带提一句,对于Object对象也存在同样的问题。请看下面的
代码: Dim FSO 或 Dim FSO as object Set FSO = New Scripting.FileSystemObject 上面的
代码由于在申明的时候没有指定数据类型,在赋值时将浪费内存和
cpu时间。正确的
代码: Dim FSO as New FileSystemObject 3. 尽量避免使用
属性 在平时的
代码中,最常见的比较低效的
代码就是在可以使用变量的情况下,反复使用
属性(Property),尤其是在循环中。要知道存取变量的速度是存取
属性的速度的20倍左右。 Dim intCon as Integer For intCon = 0 to Ubound(SomVar()) Text1.Text = Text1.Text & vbcrlf & SomeVar(intCon) Next intCon 下面这段
代码的执行速度是上面
代码的20倍。 Dim intCon as Integer Dim sOutput as String For intCon = 0 to Ubound(SomeVar()) sOutput = sOutput & vbCrlf & SomeVar(intCon) Next Text1.Text = sOutput 4. 尽量使用数组,避免使用集合 除非你必须使用集合(Collection),否则你应该尽量使用数组。据测试,数组的存取速度可以达到集合的100倍。这个数字听起来有点骇人听闻,但是如果你考虑到集合是一个对象,你就会明白为什么差异会这么大。 5. 展开小的循环体 在编码的时候,有可能遇到这种情况:一个循环体只会循环2到3次,而且循环体由几行
代码组成。在这种情况下,你可以把循环展开。原因是循环会占用额外的
cpu时间。 6. 避免使用很短的
函数 和使用小的循环体相同,
调用只有几行
代码的
函数也是不经济的--
调用函数所花费的时间或许比执行
函数中的
代码需要更长的时间。在这种情况下,你可以把
函数中的
代码拷贝到原来
调用函数的地方。 7. 减少对子对象的引用 在VB中,通过使用.来实现对象的引用。例如: Form1.Text1.Text 在上面的例子中,程序引用了两个对象:Form1和Text1。利用这种
方法引用效率很低。但遗憾的是,没有办法可以避免它。程序员唯一可以做就是使用With或者将用另一个对象保存子对象(Text1)。 ' 使用With With frmMain.Text1 .Text = "Learn VB" .Alignment = 0 .Tag = "Its my life" .BackColor = vbBlack .ForeColor = vbWhite End With 或者 ' 使用另一个对象保存子对象 Dim txtText
Box as Text
Box Set txtText
Box = frmMain.Text1 TxtText
Box.Text = "Learn VB" TxtText
Box.Alignment = 0 TxtText
Box.Tag = "Its my life" TxtText
Box.BackColor = vbBlack TxtText
Box.ForeColor = vbWhite 注意,上面提到的
方法只适用于需要对一个对象的子对象进行操作的时候,下面这段
代码不正确: With Text1 .Text = "Learn VB" .Alignment = 0 .Tag = "Its my life" .BackColor = vbBlack .ForeColor = vbWhite End With 很不幸的是,我们常常可以在实际的
代码中发现类似于上面的
代码。这样做只会使
代码的执行速度更慢。原因是With块编译后会形成一个分枝,会
增加了额外的处理工作。 8. 检查字符串是否为空 大多数程序员在检查字符串是否为空时会使用下面的
方法: If Text1.Text = "" then End if 很不幸,进行字符串比较需要的处理量甚至比读取
属性还要大。因此建议大家使用下面的
方法: If Len(Text1.Text) = 0 then End if 9. 注意Next关键字后的变量名 在Next关键字后
加上变量名会导致
代码的效率下降。我也不知道为什么会这样,只是一个经验而已。不过我想很少有程序员会这样画蛇添足,毕竟大多数程序员都是惜字如金的人。 '
错误的
代码 For iCount = 1 to 10 ' 执行操作 Next ' 正确的
代码 For iCount = 1 to 10 ' 执行操作 Next iCount 10. 使用数组,而不是多个变量 当你有多个保存类似数据的变量时,可以考虑将他们用一个数组代替。在VB中,数组是最高效的数据结构之一。 11. 使用动态数组,而不是静态数组 使用动态数组对
代码的执行速度不会产生太大的影响,但是在某些情况下可以节约大量的资源。 12. 销毁对象 无论编写的是什么软件,程序员都需要考虑在
用户决定终止软件运行后释放软件占用的内存空间。正确的做法是在
退出程序前需要销毁程序中使用的对象。如: Dim FSO as New FileSystemObject ' 执行操作 ' 销毁对象 Set FSO = Nothing 对于窗体,可以进行卸载: Unload frmMain 或 Set frmMain = Nothing 13. 变长和定长字符串 从技术上来说,与变长字符串相比,定长字符串需要较少的处理时间和空间。但是定长字符串的缺点在于在很多情况下,你都需要
调用Trim
函数以
去除字符串末的空字符,这样反而会降低
代码效率。所以除非是字符串的长度不会变化,否则还是使用变长字符串。 14. 使用类模块,而不是ActiveX控件 除非ActiveX控件涉及到
用户界面,否则尽量使用轻量的对象,例如类。这两者之间的效率有很大差异。 15. 使用内部对象 在涉及到使用ActiveX控件和DLL的时候,很多程序员喜欢将它们编译好,然后再加入工程中。我建议你最好不要这样做,因为从VB连接到一个外部对象需要耗费大量的
cpu处理能力。每当你
调用方法或存取
属性的时候,都会浪费大量的系统资源。如果你有ActiveX控件或DLL的源
代码,将它们作为工程的私有对象。 16. 减少模块的
数量 有些人喜欢将通用的
函数保存在模块中,对于这一点我表示赞同。但是在一个模块中只写上二三十行
代码就有些可笑了。如果你不是非常需要模块,尽量不要使用它。这样做的原因是因为只有在模块中的
函数或变量被
调用时,VB才将模块加载到内存中;当VB应用程序
退出时,才会从内存中卸载这些模块。如果
代码中只有一个模块,VB就只会进行一次加载操作,这样
代码的效率就得到了提高;反之如果
代码中有多个模块,VB会进行多次加载操作,
代码的效率会降低。 17. 使用对象数组 当设计
用户界面时,对于同样类型的控件,程序员应该尽量使用对象数组。你可以做一个实验:在窗口上
添加100个Picture
Box,每个 Picture
Box都有不同的
名称,运行程序。然后创建一个新的工程,同样在窗口上
添加100个Picture
Box,不过这一次使用对象数组,运行程序,你可以注意到两个程序加载时间上的差别。 18. 使用Move
方法 在改变对象的位置时,有些程序员喜欢使用Width,Height,Top和Left
属性。例如: Image1.Width = 100 Image1.Height = 100 Image1.Top = 0 Image1.Left = 0 实际上这样做效率很低,因为程序
修改了四个
属性,而且每次
修改之后,窗口都会被重绘。正确的做法是使用Move
方法: Image1.Move 0,100,100 19. 减少
图片的使用
图片将占用大量内存,而且处理
图片也需要占用很多
cpu资源。在软件中,如果可能的话,可以考虑用背景色来替代
图片--当然这只是从技术人员的角度出发看这个问题。 20. 使用ActiveX DLL,而不是ActiveX控件 如果你设计的ActiveX对象不涉及到
用户界面,使用ActiveX DLL。 来源:http://www.mndsoft.com/blog/article.asp?id=430 编译优化 我所见过的很多VB程序员从来没有使用过编译选项,也没有试图搞清楚各个选项之间的差别。下面让我们来看一下各个选项的具体含义。 1.P-
代码(伪
代码)和本机
代码 你可以选择将软件编译为P-
代码或是本机
代码。缺省选项是本机
代码。那什么是P-
代码和本机
代码呢? P-
代码:当在VB中执行
代码时,VB首先是将
代码编译为P-
代码,然后再解释执行编译好的P-
代码。在编译环境下,使用这种
代码要比本机
代码快。选择P-
代码后,编译时VB将伪
代码放入一个EXE
文件中。 本机
代码:本机
代码是VB6以后才推出的选项。当编译为EXE
文件后,本机
代码的执行速度比P-
代码快。选择本机
代码后,编译时VB使用机器指令
生成EXE
文件。 在使用本机
代码进行编译时,我发现有时候会引入一些莫名其妙的
错误。在编译环境中我的
代码完全正确地被执行了,但是用本机
代码选项
生成的EXE
文件却不能正确执行。通常这种情况是在卸载窗口或弹出打印窗口时发生的。我通过在
代码中加入DoEvent语句
解决了这个问题。当然出现这种情况的几率非常少,也许有些VB程序员从来没有遇到过,但是它的确存在。 在本机
代码中还有几个选项: a)
代码速度优化:该选项可以编译出速度较快的执行
文件,但执行
文件比较大。推荐使用 b)
代码大小优化:该选项可以编译出比较小的执行
文件,但是以牺牲速度为代价的,不推荐使用。 c) 无优化:该选项只是将P-
代码转化为本机
代码,没有做任何优化。在调试
代码时可以使用。 d) 针对Pentium Pro优化:虽然该项不是本机
代码中的缺省选项,但是我通常会使用该选项。该选项编译出的可执行程序在Pentium Pro和Pentium 2以上的机器上可以运行得更快,而在比较老的机器上要稍稍慢一些。考虑到现在用Pentium 2都是落伍,所以推荐大家使用该选项。 e) 产生符号化调试信息:该项在编译过程中
生成一些调试信息,使
用户可以利用Visual C++一类的工具来调试编译好的
代码。使用该选项会
生成一个.pdf
文件,该
文件记录了可执行
文件中的标志信息。当程序拥有API
函数或DLL
调用时,该选项还是比较有帮助的。 2. 高级优化 高级优化中的设置可以帮助你提高软件的速度,但是有时候也会引入一些
错误,因此我建议大家尽量小心地使用它们。如果在
代码中有比较大的循环体或者复杂的数学运算时,选中高级优化中的某些项会大幅度提升
代码的
性能。如果你使用了高级优化
功能,我建议你严格测试编译好的
文件。 a) 假定无别名:可以提高循环体中
代码的执行效率,但是在如果通过变量的引用改变变量值的情况下,例如
调用一个
方法,变量的引用作为
方法的参数,在
方法中改变了变量的值的话,就会引发
错误。有可能只是返回的结果
错误,也有可能是导致程序中断运行的严重
错误。 b) 取消数组绑定检查、取消整数溢出检查和取消浮点
错误检查:在程序运行时,如果通过这些检查发现了
错误,
错误处理
代码会处理这些
错误。但是如果取消了这些检查,发生了
错误程序就无法处理。只有当你确定你的
代码中不会出现上面的这些
错误时,你才可以使用这些选项。它们将使软件的
性能得到很大的提升。 c) 允许不舍入的浮点操作:选择该选项可以是编译出来的程序更快地处理浮点操作。它唯一的缺点就是在比较两个浮点数时可能会导致不正确的结果。 d) 取消Pentium FDIV安全检查:该选项是针对一些老的Pentium芯片设置的,现在看来已经过时了