Symbian OS C++程序员编码诀窍 (二)

 3    系统资源的使用(ROM 和 RAM )

  3.1      重要性

       移动电话是一种资源有限设备。然而,它却存在大量的可用功能,这对现有的系统资源提出了很高的要求。开发者需要注意这些制约,尽可能地少用这些有限的资源。

3.2      减少代码量

     最终编译后的代码必须尽可能得小,以便为设备留出尽可能多的可用空间,这一点非常重要。以下诀窍就如何保证不浪费存储空间提供了一些指导性意见。为解决这一问题,你需要花一点时间去检查代码,同时还要考虑一些其他的方法,使得编译后的代码量变小。

3.2.1    不必要的导出函数

       当使用IMPORT_C和EXPORT_C 从某个DLL 中导出一些函数时,它们会因为导出表而耗尽空间。只需要导出那些必需在该DLL 外使用的函数。

3.2.2    复制和粘贴

      复制和粘贴经常导致代码臃肿。当需要重用其他模块中的代码时,请向自己提问下列问题: 
      1.  这段代码是否实际需要? 
      2.   为此任务是否复制了过多的代码? 
     3.  如果将该函数提取到某个基类,或到一个帮助模块,使一个以上的地方都能使用它,这样是不是更好? 
      4.   针对所需任务,该代码是否能重写,使其更为有效,而不是去复制那些接近需求的东西?

3.2.3    明显不可分解的函数

      在许多地方,一些函数出现在同一个类中,这些函数实现非常类似的任务。经常的情况是:可以把这些公共代码提取到一个单一的函数中去,对该函数实施参数化,以便完成所需的不同任务。

3.2.4    过分的TRAP模块

      当编译错误捕捉代码模块时,它们会消耗内存空间。含有许多TRAP宏的代码 (如,在一个类中含有五个以上的TRAP宏)将消耗太多的空间。另一种可能的情形是:设计不正确,使得TRAP模块不是广泛地用于正常代码。在这里,我们允许高级开发工作中有特别的出错处理和恢复程序。

3.2.5    调试发行代码

       如果有任何用于登录、调试,或测试的代码,必须将它们从发布版中剔除。可以为此目的使用编译指示#ifdef _DEBUG。

3.2.6    不必要的虚函数

       不必要的虚函数是有害的,原因类似于函数导出,它们会创建额外的vtable(虚表)函数。

 3.2.7    使用公共控件

       如果可能,请使用系统 (或其它共享DLL )提供的框架控件,而不是去开发新的控件。

3.2.8    _L 宏的误用

       现在已经不建议使用带字母_L 的宏了,取而代之的是效率更高的_LIT宏。

3.3      减少使用RAM

      有许多方法可以减少RAM 的使用。其中的一些方法(如bitfields)可能使代码可读性变差,所以经常要在减少RAM 使用和增加代码复杂性这两者之间作折衷。

3.3.1    使用bitfields  (位元组合),而不使用太多的Tbools,考虑用bitfields  (位元组合)来存储类中大量的布尔数据。每一个Tbool 需要32位的RAM,而这32 位可以用位元组合的形式保存32 个布尔值。如上所述,我们可以比较一下:提高代码复杂性和使用bitfields 各自的潜在利益。

3.3.2    阵列粒度的使用警示

       可以为所有继承自CArray 的类规定粒度。其目的是:只以一定大小的块为阵列分配空间,从而使代码更为高效。这种方法很有效,但需要考虑粒度的选取问题。如果需要为5至8个对象准备一个阵列,那么粒度定为4到5就是明智的。如果一个阵列总是含有15个对象,那么粒度就应该定为15。然而,如果对象的数目是2个到3个,那么粒度定为100就很愚蠢了。类似的,如果有101到105个对象,那么粒度为100也是愚蠢的,因为每次都需要分配200个空间。当然,粒度为1也属不智,因为这将需要太多次的重新分配。最终选择取决于使用方式。

3.3.3    避免全局数据

        不要使用全局数据。对于只用于一个函数内的变量,请用局部变量,而不是成员变量。

3.3.4    小心基类的成员数据

      如果要写一个用途广泛的基类,请小心成员数据。不要将只用于某些继承类的成员数据添加其中,因为每个继承类除了拥有它,别无其他选择。注意只将真正普通的成员函数包括其中。

3.3.5    正确使用清除堆栈

        如果正确地使用了清除堆栈,代码中就不应该再有内存泄漏,这样就能保证该应用没有使用超出其需要的RAM 。

3.3.6    尽早删除

       如果在堆中分配了临时对象,当不再需要它们时请将其立即删除。如果这些临时对象的生命长于其需要的时间,那么该应用的RAM 开销往往要高于其实际所需要的。请记住,如果删除了某个临时对象,而指向这个对象的指针还在,那么就需要将该指针设为NULL,以防止非法访问或两次删除。

3.3.7    用最大数据集进行硬件测试

      如果某个数据集有上限,那么就用最大数据集来进行硬件测试。如果从来没有对硬件进行过极限测试,很有可能会忽略某些非常慢的运算,或导致问题等。

3.3.8    分解复杂的长运算

       在屏幕上显示冗长列表会对RAM 使用形成压力。而且,当初始化各列表控件(如:设备上所有联系人的列表,或便条列表)时,其表现极差。可以编写特别的控件来避免这种情况,这些控件只组装屏幕上可见的栏目。当滚动时,释放那些离开了屏幕区的栏目,同时添加新出现的栏目。

3.4      减少堆栈的使用

     目标硬件上某个应用可用的堆栈比起Windows NT 环境中模拟器可用的巨量堆栈来要小得多。结果是:在WINS 模拟器中能良好运行的代码在硬件中却不能运行,而且出现很明显的随机性严重提示(panic)。减少堆栈使用并不容易,但还是需要引起密切的关注。

3.4.1    正确使用描述符

       有两种类型的描述符,即堆描述符(HBufC)和栈描述符(HBufC)。所有的描述符都使用其中之一来储存。当栈溢出时,90%时间是由栈中大型的描述符引起的。小心对待那些将导致隐含复制描述符的那些操作,并尽可能避免这种情况的出现。在某些情况下,最好分配HbufCs,而不是Tbufs。

       某些相关的Symbian OS 类,如Tparse,也能开销掉许多栈空间。可以考虑使用那些耗费栈空间较少的版本 (如:TParseBase)。 向描述符传参数比传值更好。

 3.4.2    小心使用递归,在限度内生成

        如果需要递归程序,请注意栈需求。应该努力降低向下传递的参数的大小,并力图将本地自动变量移出该函数的递归部分。尽可能地在递归限制深度内生成(build )代码,以免栈溢出。

3.4.3    注意登录代码

        登录代码往往涉及到对超长描述符及将其写入到文件中的格式化工作。由于这一理由,它们往往成为栈溢出的原因。

3.5      盘容量降低的处理

       对闪存文件系统(Flash File System,FFS,其别名是C:驱动器)上可用自由空间的监测系统,我们定 义了两个级别:警示级(Warning Level,WL )和临界级 (Critical Level,CL )。当自由磁盘空间遇到这些级别中的一个时,系统 (EikSrvUI)将显示一个全局提示,向用户发出有关当前情势的警 示。此后各种应用程序和服务器就忽略掉警示级而专注于临界级。 所有对磁盘文件以已知的文件尺寸进行创建或写入操作都必须首先以那个尺寸作为方法 FFSSpaceBelowCriticalLevelL 的参数来检查临界级。如果磁盘空间已经很低,或者说已经低于临界级,这个方法就会返回Etrue。应用程序就不能再进行写入操作,同时通知用户,磁盘已 满。(用KerrDiskFull 出错代码作异常退出可以达到这个目的。)

 所有对磁盘文件以一个不知的文件尺寸进行创建或写入操作都必须先检查临界级,向方法FFSSpaceBelowCriticalLevelL传递一个合适的预估尺寸或‘0’(默认)作为参数。这里的‘0’可用于检查是否已经低于临界级了。

       比较麻烦的情况是在几个数据库(如联系人)中创建单一项目。在这些情况中,可以使用一个预估值,用作因添加该项目而需要的数据库尺寸增量。

             SysUtil.h/SysUtil.dll 中有临界级检查方法。其API 看上去如下所示:

             /**
              * Checks if the free FFS (internal Flash File System) storage
              * space is or will fall below Critical Level (CL).
              * The CL and FFS drive letter is defined by this module.
              * @param aFs File server session.
              *  Must be given if available in the caller,
              *  e.g. from EIKON environment.
              *  If NULL this method will create a temporary session for
              *  a check, but then the check is more expensive.
              * @param aBytesToWrite number of bytes the caller is about to add
              *  FFS, if known by the caller beforehand.
              *  The default value 0 checks if the current
              *  space is already below the CL.
              * @return ETrue if storage space would go below CL after adding
              *  aBytes more data, EFalse otherwise.
              *  Leaves on error.
              */
             IMPORT_C static TBool FFSSpaceBelowCriticalLevelL(
             RFs* aFs, TInt aBytesToWrite = 0);

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值