RSS订阅 | 匿名投稿
您的位置:网站首页 > 系统 > 正文

DELPHI编写服务程序总结

作者:admin 来源: 日期:2012/5/21 12:14:54 人气: 标签:

五、函数递归
如果存在递归函数,就需要特别注意,是否会正常退出函数执行,如果一直执行下去,会把程序调用堆栈全部吃完,导致程序异常终止,如下例:只要一点btn1,程序就会无声无息死掉,而且没有LOG,这类代码在以服务方式运行需要特别注意,因为你的服务是无人值守的情况下运行的,如果出现这种情况,你的服务会直接退出,而且没有任何提示,对于查找问题无从下手。
procedure TForm1.btn1Click(Sender: TObject);
procedure Recursive;
begin
Recursive;
end;
begin
Recursive;
end;
六、消息重入
消息重入的概念是:有一个消息执行过程还没有执行,相同的一个消息又进入相同的函数处理。消息重入很大原因是在很多软件中调用Application.ProcessMessage来更新界面,如果是一个操作需要很长的时间,可以改为线程来执行,或者不调用Application.ProcessMessage函数。例如:下面的函数就很容易导致消息重入。
procedure TForm1.btn1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 10000000 do
begin
Application.ProcessMessages;
end;
end;
如果必须要用Application.ProcessMessage来更新界面,你应该确保在函数执行过程中,这个消息不会第二次投递,如这个例子你可以通过把btn1的状态禁用来防止消息重入,正确的写法是:
procedure TForm1.btn1Click(Sender: TObject);
var
i: Integer;
begin
btn1.Enabled := False;
for i := 0 to 10000000 do
begin
Application.ProcessMessages;
end;
btn1.Enabled := True;
end;
另外在发送消息的时候,也需要特别注意SendMessage和PostMessage的区别,SendMessage是发送等待消息处理完成再返回,PostMessage是投递到消息缓冲池排队,立即返回(这时消息可能没有处理),消息需要等到轮到它的时候再处理。
七、野指针
野指针在编译时候是无法检测的,只有在运行时候才会出现,出现野指针最常见的错误就是Access violation错误(简称AV错误),出现这种错误是你指向的物理内存不可用。出现野指针主要是由于以下四种引起:1、指针变量没有初始化;2、指针被Free或Dispose之后再次使用;指针操作超越了变量的范围;4、取string的地址,没有判断string是否已经分配内存。
代码在判断指针是否是空指针是通过判断指针的值是否介于0x00000000和0x0000FFFF之间,如果在这之间用if语句是可以判断,如果不介于这之间,则认为指针是有效的。因此指针在申请之后或者释放之后,指向的地址是随机值,因此用if语句是无法判断。另外在DELPHI中,你把指针置为nil,翻译成汇编代码就是异或一下,可以打开CPU窗口查看,如:
Fm := nil;生成的汇编是:xor eax eax,即把指针置为0x00000000。

八、内存泄漏
内存泄漏指的是软件在运行过程中对于申请的内存空间没有释放,导致内存占用越来越大,最后程序异常崩溃,而且此时也不会留下任何痕迹,没有任何系统日志可查。内存泄漏也分为两种,一种是程序一起动,然后占用了内存,不会随着程序运行增长;一种是随着程序运行不停增长的;如果是第一种可以放过,对二种一定要仔细检查,检查工具推荐用FastMM,并且把DELPHI的项目属性Compiler->Use Debug DCUs和Linker->Map file->Detailed选中,这样FastMM就可以把申请内存的调用堆栈和MAP地址打出来,非常利于查找内存泄漏。查找内存泄漏一般可以从以下几个方面考虑:
1. 使用Dispose释放内存的时候要加上定义信息,如果不加定义信息,对于一些指针或者string释放不了,对于结构体内部有指针的应先释放内部指针;
2. 使用FreeMem或FreeMemory释放内存的时候,可以不加大小信息,这是因为DELPHI内存管理器内部知道指针大小信息;
3. Override函数一定要inherited来释放父类申请的内存;
4. 申请的内存要确保释放,可以用Try … finally … end来确保内存的释放,但是应杜绝这种代码风格try …申请内存…finally …释放内存… end;
5. 系统内核对象要确保关闭;
6. 申请的指针如果在某些情况下分配空间,要记得初始化为nil,释放的时候要判断是否为空,因为释放空指针也会导致内存泄漏;
7. 另外PostMessage也有可能导致内存泄漏,这种情况是通过PostMessage发送结构体,释放内存放在消息处理函数中,这时如果频繁的调用PostMessage,消息处理循环忙不过来,就会丢掉一些消息,造成内存泄漏,默认的Windows消息队列长度是4000,如果说消息队列有4000个,你这时再用PostMessage投递消息,就会被丢掉,造成申请的结构体无法释放,造成内存泄漏;
九、并发
如果程序涉及多线程,而且线程之间有协作关系,如果这时线程挂死了,就要查线程同步,一般这类问题比较难查,而且需要对代码执行流程非常了解,属于比较难以处理的一类问题。可以借助一些三方工具,比如“procexp.exe”就是一个非常优秀的工具,用他可以看到每个线程的状态,如果一个线程停在哪不动,你就可以通过MAP地址和调用堆栈找到问题点。如Excel的线程状态如下图:



十、一些有效的建议
针对以上的这些问题,我们在日常的开发中,应该注意哪些问题呢,下面是我给出的一些建议:
1.探索需求,需求理解越深写出代码的质量、架构就越轻巧,可读性和维护性大大提高;
2. 测试驱动开发;
3. 良好的代码风格,良好的编码习惯对于软件质量有非常大的提高;
4. 变量(指针、数组)被创建之后应及时把他们初始化;
5. 检查变量的初始值、缺省值错误,或者精度不够;
6. 类型转换,一定要善用as和is;
7. 检查变量上溢或下溢,数组越界;
8. 检查I/O错误,I/O不是总返回真的;
9. 数据结构够用就好,不要设计面面俱到、非常灵活的数据结构;
10. 差劲的代码,不要想着改改又可用了,应当重新编写,因为极有可能导致按下葫芦浮起瓢;
11. 对程序编译出现的每一个告警,都认真对待,要编写无警告的代码;
12. 对于不需要修改的参数带上const,不但可以提高效率,而且可以增强安全;


读完这篇文章后,您心情如何?
0
0
0
0
0
0
0
0
本文网址: