用友软件股份有限公司研发过程 U9 性能规范 文件编号:U9-SE-CD-WF-003 版 本 号 :V1.0 修改状态: 编 写 人 :张红斌、尹明君、黄卫 审 核 人 :翟宇翔 批 准 人 :黄涛 批准时间:2006-10-30 第 1 页 共 55 页 1. 适用对象 该规范适用于 U9 设计人员和开发人员。 2. 版本记录 此部分要记录该文档形成过程中的历次版本变更过程及变更的内容 版本 修改与参与人 修改时间 修改原因 修改概述 审批人 1.0 张红斌、尹明君、黄卫 2006/06/10 原始文档建立 1.1 张红斌 2007/01/29 补充内容 1. ToEntityData 消耗 2. A.B 代替 A.B.ID 3. 新的 EntityFinder.IsExists 方法 4. UI 禁用 Entity 对象 5. 使用 throw 而不是 throw e 2.0 张红斌 2008/03/10 形成针对 U9 V1.1 版的性能规范 结合 V1.0 开发过程中发现的一些问题,对性能规范进行了补充和完善。 《性能规范》:补充 U9 编程模型 1.1.14节至 1.1.17 节。 《Performance checklist》:补充 BP&BE和 UI 部分,新增 DB 部分。 黄涛 3. 相关文档 此部分包含对该文档起指导与约束作用的相关文档以及预计在该文档指导与约束下将要建立的文档。 4. 约定 标有 ★ 的条目表示强制性规范。 第 2 页 共 55 页 性能规范细则 1.基础篇 2.C#语言 2.1 垃圾回收 垃圾回收是现代语言的标志之一。垃圾回收解放了手工管理对象释放的工作,提高了程序的健壮性,但副作用就是程序代码可能对于对象创建变得随意。 2.1.1 避免不必要的对象创建 由于垃圾回收的代价较高,所以 C#程序开发要遵循的一个基本原则就是避免不必要的对象创建。以下列举一些常见的情形。 2.1.1.1. 避免循环创建对象 ★ 如果对象并不会随每次循环而改变状态,那么在循环中反复创建对象将带来性能损耗。例如下例: 高效的做法是将 builder 对象提到循环外面创建。 2.1.1.2. 在需要的逻辑分支中创建对象 如果对象只在某些逻辑分支中才被用到,那么应只在该逻辑分支中创建对象。例如: 正确的做法是: 第 3 页 共 55 页 2.1.1.3. 使用常量避免创建对象 如下例,程序中存在大量 new decimal(0)的代码,这会导致小对象频繁创建及回收: 正确的做法是使用 Decimal.Zero 常量。另外,我们也可以学习这个设计手法,应用到类似场景中。 2.1.1.4. 使用 StringBuilder 做字符串连接 请参见 1.2.1 节。 2.1.2 不要使用空析构函数 ★ 如果类包含析构函数,则创建对象时会在 Finalize 队列中添加对象的引用,以保证当对象无法可达时,仍然可以调用到 Finalize 方法。垃圾回收器在运行期间,会启动一个低优先级的线程处理该队列。相比之下,没有析构函数的对象就没有这些消耗。如果析构函数为空,这个消耗就毫无意义,只会导致性能降低!因此,我们要求不要使用空的析构函数。 从实际情况看,许多是曾经在析构函数中包含有处理代码,但后来因为种种原因被注释掉或者删除掉了,只留下了一个空壳。此时应注意把析构函数本身注释掉或者删除掉。 2.1.3 实现 IDisposable 接口 垃圾回收事实上只支持托管内存的回收,对于其它的非托管资源,例如 Windows GDI 句柄或数据库连接,在析构函数中释放资源有很大问题。原因是垃圾回收依赖于内存紧张情况,虽然数据库连接可能已濒临耗尽,但如果内存还很充足的话,垃圾回收是不会运行的。 C#的 IDisposable 接口是一种显式释放资源的机制。通过提供 using 语句,还简化了使用方式(编译器自动生成 try..finally 块,并在 finally 块中调用 Dispose 方法)。对于申请了非托管资源的对象,应为其实现 IDisposable 接口,以保证资源一旦超出 using 语句范围,即得到及时释放。这对于构造健壮且性能优良的程序非常有意义! 为防止对象的 Dispose 方法不被调用的情况发生,一般还要提供析构函数,两者调用一个处理资源释放的公共方法。同时,Dispose 方法应调用 System.GC.SuppressFinalize(this),告诉垃圾回收器无需再处理Finalize 方法了。 2.2 String 操作...