Delphi 代码优化
分类: Delphi 2008-03-16 07:59
?
1. 字符串优化
o o o o o o ? o o o o o o ? o o o o o o o ? o o o o o o o o o o o o o o o o o o
1.1. 不重复初始化 1.2. 使用 SetLength 预分配长字符串(AnsiString) 1.3. 字符串与动态数组的线程安全(Thread Safety) 1.4. 避免使用短字符串 1.5. 避免使用 copy 函数 1.6. 总是使用长字符串,必要时转换为 pchar 2.1. 尽量使用 32 位变量 2.2. 避免使用子界类型 2.3. 简化表达式 2.4. 不再畏惧乘法 2.5. 临时子界类型 2.6. 大整数运算 3.1. 警惕 Extended 3.2. 改变 FPU 控制字 3.3. 多用 Round 3.4. 传送实参 3.5. 自己动手,丰衣足食 3.6. 减少除法 3.7. 浮点零的检查 4.1. 局部变量 4.2. 局部过程 4.3. 过程参数 4.4. 指针变量 4.5. 数组 4.6. 流程控制 4.7. 强制类型转换 4.8. 枚举、集合 4.9. Pentium II 带来的新问题 4.10. CPU 视图 4.11. 循环语句 4.12. case 语句 4.13. 填充和移动内存 4.14. 接口和虚方法 4.15. 代码对齐 4.16. 代码风格 4.17. 相信编译器 4.18. 代码计时
2. 整数代码优化
3. 浮点优化
4. 其他优化
o
4.19. 写在最后
字符串优化
delphi 有三种字符串类型:短字符串(string[n],n=1..255)存储区为静态分配,大小在编译时确定,这 是继承于 bp for dos 的类型;字符数组(pchar)主要是为了兼容各类 api,在 bp7 中已经出现,如今在 delphi 中更加应用广泛,其存储区可以用字符数组静态分配,也可用 getmem 手动分配;而长字符串 (ansistring)是 delphi 独有的,其存储区在运行时动态分配,最灵活也最易被滥用。
不重复初始化
delphi 默认字符串类型 AnsiString 会自动初始化为空。如下代码:
var s:string; begin s:=""; …… end;
s:="";就属多此一举。但是值得注意的是这对函数返回值 result 无效。而一般说来,用 var 实 参传递比返回字符串值要更快一些。
预分配长字符串( 使用 SetLength 预分配长字符串(AnsiString) )
动态分配内存是 AnsiString 的一大长项,但容易弄巧成拙,一个典型的例子如下:
s2:=" "; for i:=2 to length(s1) do s2:=s2+s1[i];
且不说可用 delete 取代之,主要问题在于上例的循环中 s2 的内存区域被不停地重复分配,相 当费时。一个简单有效的办法如下:
setlength(s2,length(s1)-1); for i:=2 to length(s1) do s2[i-1]:=s1[i];
这样 s2 内存只会重新分配一次。
字符串与动态数组的线程安全(Thread Safety) 字符串与动态数组的线程安全
在 delphi 5 以前动态数组与长字符串的操作这些非线程安全调用是由引用计数来处理其临界问题的, 而自 delphi5 起就改为直接在一些临界指令前加 lock 指令前缀来避免这个
问题。 不幸的是这一修改的代价相当 昂贵, 因为在 pentiumⅱ处理器中 lock 指令相当费时, 大概要耗费额外的 28 个
指令周期来完成这一操作, 因而整体效率至少下降一半。解决这个问题的办法只有一个,那就是修改 delphi rtl 核心代码。在备份原 文件后,将 source\rtl\sys\system.pas 中所有的 lock 替换为{lock},当然必须是整字替换。如此还未
完全优化,下一步是将 delphi4 运行库中也有的 xchg 指令去掉,因为该指令有隐含的 lock 前缀,所以必 须将 system.pas 内_lstrasg 和_strlasg 两个过程中的 xchg edx,[eax] 替换为如下代码:
mov ecx,[eax] mov [eax],edx mov edx,ecx
ok 大功告成,编译一下,覆盖 system.dcu 即可。如此其执行效率将比 delphi5 提高 6 倍,比 delphi4 提高 2 倍。
避免使用短字符串
由于很多字符串操作会先把短字符串转换为长字符串,从而减慢了执行速度,因此还是少使用短字符串为 妙。
避免使用 copy 函数
这也和滥用内存管理有关。一个典型的情形如下:
if copy(s1,23,64)=copy(s2,15,64) then ……
这样导致分配了两块临时内存,因而降低了效率。应当替换为如下代码:
i:=0; f:=false; repeat f:=s1[i+23]<>s2[i+15]; inc(i); until f or (i>63); if not f the