代码性能调整(12个问题)

翻译: 代码性能调整

本文译自: Performance Tuning of Code
应用程序运行正常,可以执行用户或客户所需的所有任务,并不意味着程序在任何方面都是完美的。 使用性能分析工具,比如profiler,我们就能明白程序在内部是如何运行的,在速度、内存占用、 电量使用等方面的情况。 能降低你的应用程序性能的问题有许多,下面我将列举一些:
  • 【问题1: DLL用法优化】
在Symbian,按链接方式可分为两种类型的链接库: 静态接口的dll和多态接口的dll。通常应用 程序与许多dll静态链接,需要这些dll与否取决于不同的用况,但所有的依赖dll都装入内存将会 降低应用程序性能,这是因为应用程序或服务程序的静态依赖对自由内存有很大影响。通过把逻辑 相关的功能分割成动态可装载的部件会将静态依赖减小到最少。
void RuntimeLoadDllL()
	{
	RFs fileSession;
	User::LeaveIfError(fileSession.Connect());
	TFileName dllName;
            If ( SomeCondition )
		{
		.......
		dllName = KDllNameOne;
		}
           else
		{
		.........
		dllName = KDllNameTwo;
		}
	LoadDllL(dllName);
           .....................

	fileSession.Close();
	}

void LoadDllL(const TFileName& aLibName)
	{
	RLibrary lib;
	User::LeaveIfErrorlib.Load(aLibName));
	.....
	}
ECOM也提供了一种标准的机制可在运行时装入指定的实现。
  • 【问题2: 检查TRAP的使用情况】
TRAP的使用应尽量少,TRAP会消耗比你以为的要多的资源。因为导致内核执行机构调用TTrap::Trap() 和TTrap::UnTrap(),以及在运行时分配一个结构存放当前堆栈上下文以便万一发生leave事件时回 退到之前的状态。若你的类含有超过6个以上TRAP,意味着class设计不正确,需要重新设计。只要可能, 就把TRAP移到函数调用的更外层。
  • 【问题3: 检查服务的使用与优化】
应用程序启动时马上连接到服务是不可取的(当连接到瞬时服务时),因为这将导致连锁反应,多个服务 程序的依赖部件会装入内存。如果服务很少使用,这种方法可以看作是无效的资源使用。随需连接到瞬时 服务总是明智的。应当以这样的方式来设计,客户API的实现总是与实际的服务实现相分离,这样,当客 户端程序链接到客户API库,就不会自动装载服务程序依赖项,而这应发生在服务程序真正启动时。 在设计服务程序时总是考虑它的使用情况和运行时需要的各种资源。假定服务提供三个功能,比如读、写 和通知,读/写不是很频繁的操作。这种情况下,最好分成两个服务,一个提供重量级功能,诸如读/写/替 换等,将被按客户端需要转载/卸载,另外一个提供轻量级的通知服务。
  • 【问题4: 压缩可执行程序】
在应用程序的MMP文件使用compresstarget声明指出目标可执行文件应该被压缩。通过这样做,可执行 文件的代码和数据段以Huffman+LZ77算法压缩。这将使得存储的可执行文件在文件系统中使用更少的空 间。在被装入时,可执行文件装载器解压这个文件。所有的可执行文件不应该被解压,只有那些占用大量空 间的可选择解压。
  • 【问题5: 文件扫描】
如果盘符已知,那么总是在文件路径指定驱动盘符。若没指定盘符,将以标准的Symbian OS顺讯搜索所 有可用的驱动盘。若你的文件在Z:,那么你将有极大的损失,因为Z:总是最后才搜索到。
  • 【问题6: 检查内存使用优化】
在S60应用程序,缺省的线程堆栈大小只有8kb,因此只有很小的对象才该在栈上创建,并尽可能早地从 栈中移除。除了基本类型,我们应该总是以引用传递参数而不是按值。大对象和数组的创建应该在堆中完 成,并尽可能减小自动变量的生命周期。
  • 【问题7: 检查缺省参数的使用】
若我们为函数参数声明了缺省值,额外的代码将被编译器生成,这可能也是一个费用。若缺省值常用,那 么值得重载这个方法,而不是提供缺省参数值。
void MyFunction( TInt aCounterVal, TInt aParamLength = 2);

Can be written as :

void MyFunction( TInt aCounterVa );
void MyFunction( TInt aCounterVal, TInt aParamLength );
  • 【问题8: 检查引用和指针的使用情况】
避免按值传递大对象,总是引用或指针优先。除非可以接受NULL值,使用引用更好因为它更适合更简单易用。 引用不能被重新赋值,若你需要先指向一个对象后来指向其它的,那么就使用指针。引用总是比指针更好,因 为它更有效,基于这样的事实:编译器必须通过所有转换保留空指针的值,也就是说,编译器必须测试NULL值, 从而创建更多的指令。
  • 【问题9: 检查inline关键字和初始化列表】
inline关键字不是强制编译器那样做,完全依赖于编译器决定自己的行为。若函数较大(比如: 超过3-4行 代码)就避免使用inline。推荐使用inline方法的情况有:有一些get或set方法时; T类的简单构造函数; 以及使用瘦模板时。 关于inline方法有更多的问题,比如,实现代码改变将导致二进制的不兼容。若你有受限内存资源问题而不 是速度问题,方法调用成本优于大段的inline代码。 使用构造函数初始化列表比在构造函数体内赋值更为有效,因为使用缺省构造函数,类成员变量将自动构造, 优先于类构造函数内的那些条目。但构造函数列表不允许我们对变量做校验,因此并不总是适合的。
  • 【问题10: 检查磁盘空间问题】
在写任何代码之前,我们应该总是考虑磁盘空间问题。特别是当我们在MMC或内存卡上写一些内容时。 SysUtil有 DiskspaceBelowCriticalLevelL() and MMCSpaceBelowCriticalLevelL()之类的 API函数,这些函数在传入程序员想写字节的大小就可以调用了。调用上述方法时不必传递fileserver会话 对象,这使得它们不那么昂贵,因此否则就需要创建一个临时的会话。RFs也提供了解决这个问题的API函数。
  • 【问题11: 检查描述符的使用】
描述符被设计成是高效的,但是完全依赖于它们的使用。若有可能,尽量使用T类指针描述符诸如TPtrC和 TPtr而不是TBuf或TBufC,因为TBuf建在栈上(鲜有在堆上),只用于小字符串,一般地推荐最多16个字符。 就HBufC来说,尽量使用RBuf,因为它是优化的及其动态本质。避免创建类对象的多个局部实例,比如: TFileName、TParse等等,用成员变量更佳。 避免使用_L宏,因为与构造临时描述符对象有关的额外运行时成本,这也是它们在产品代码中被作废的原因。
  • 【问题12: 检查数组的使用】
数组的使用完全依赖于需要。若数组大小在编译时已知,那么可以用TFixedArray。然而绝大多数情况下需要 动态数据,我们可以用CArrayXXXX或指针型数组比如CArrayPtrFlat、CArrayPtrSeg和RPointerArray。 一般地,我们总是优先使用RArray或RPointerArray,而不是CArray或CArrayPtr。 基于运行时扩展的需要,我们可以考虑使用Segmented或Flat类型。在Flat数据上迭代是很快的因为连续,而 segment数组的扩展是很快的,因为内部实现为链表。
 【译者:建议 在写程序之前就可以考虑上述问题,而不必等到代码写完之后再去调优。】
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值