來源: Nokia Forum
重要性
行動電話是一種資源有限裝置。然而,它卻存在大量的可用功能,這對現有的系統資源提出了很高的要求。開發人員需要注意這些制約,儘可能地少用這些有限的資源。
減少代碼量
最終編譯後的代碼必須儘可能得小,以便為裝置留出儘可能多的可用空間,這一點非常重要。以下訣竅就如何保證不浪費儲存空間提供了一些指導性意見。為解決這一問題,你需要花一點時間去檢查代碼,同時還要考慮一些其他的方法,使得編譯後的代碼量變小。
不必要的匯出函數
當使用 IMPORT_C和EXPORT_C從某個 DLL 中匯出一些函數時,它們會因為匯出表而耗盡空間。只需要匯出那些必需在該 DLL 外使用的函數。
複製和粘貼
複製和粘貼經常導致代碼臃腫。當需要重用其他模組中的代碼時,請向自己提問下列問題:
1. 這段代碼是否實際需要?
2. 為此任務是否複製了過多的代碼?
3. 如果將該函數提取到某個基類,或到一個協助模組,使一個以上的地方都能使用它,這樣是不是更好?
4. 針對所需任務,該代碼是否能重寫,使其更為有效,而不是去複製那些接近需求的東西?
明顯不可分解的函數
在許多地方,一些函數出現在同一個類中,這些函數實現非常類似的任務。經常的情況是:可以把這些公用代碼提取到一個單一的函數中去,對該函數實施參數化,以便完成所需的不同任務。
過分的TRAP模組
當編譯錯誤捕捉代碼模組時,它們會消耗記憶體空間。含有許多 TRAP宏的代碼(如,在一個類中含有五個以上的 TRAP宏)將消耗太多的空間。另一種可能的情形是:設計不正確,使得 TRAP模組不是廣泛地用於正常代碼。在這裡,我們允許進階開發工作中有特別的出錯處理和恢複程式。
調試發行代碼
如果有任何用於登入、調試,或測試的代碼,必須將它們從發布版中剔除。可以為此目的使用編譯指示#ifdef_DEBUG。
不必要的虛函數
不必要的虛函數是有害的,原因類似於函數匯出,它們會建立額外的 vtable(虛表)函數。
使用公用控制項
如果可能,請使用系統(或其它共用 DLL)提供的架構控制項,而不是去開發新的控制項。
_L宏的誤用
現在已經不建議使用帶字母_L的宏了,取而代之的是效率更高的_ LIT宏。
減少使用RAM
有許多方法可以減少 RAM 的使用。其中的一些方法(如 bitfields)可能使代碼可讀性變差,所以經常要在減少 RAM 使用和增加代碼複雜性這兩者之間作折衷。
使用 bitfields(位元組合), 而不使用太多的 Tbools考慮用 bitfields(位元組合)來儲存類中大量的布爾資料。每一個Tbool需要 32位的RAM,而這32 位可以用位元組合的形式儲存 32 個布爾值。如上所述,我們可以比較一下:提高代碼複雜性和使用 bitfields 各自的潛在利益。
陣列粒度的使用警示
可以為所有繼承自 CArray 的類規定粒度。其目的是:只以一定大小的塊為陣列分配空間,從而使代碼更為高效。這種方法很有效,但需要考慮粒度的選取問題。如果需要為 5 至 8 個對象準備一個陣列,那麼粒度定為 4 到 5 就是明智的。如果一個陣列總是含有15個對象,那麼粒度就應該定為15 。然而,如果對象的數目是 2 個到 3 個,那麼粒度定為 100就很愚蠢了。類似的,如果有 101到 105個對象,那麼粒度為 100也是愚蠢的,因為每次都需要分配 200個空間。當然,粒度為 1也屬不智,因為這將需要太多次的重新分配。最終選擇取決於使用方式。
避免全域資料
不要使用全域資料。對於只用於一個函數內的變數,請用局部變數,而不是成員變數。
小心基類的成員資料
如果要寫一個用途廣泛的基類,請小心成員資料。不要將只用於某些繼承類的成員資料添加其中,因為每個繼承類除了擁有它,別無其他選擇。注意只將真正普通的成員函數包括其中。
正確使用清除堆棧
如果正確地使用了清除堆棧,代碼中就不應該再有記憶體流失,這樣就能保證該應用沒有使用超出其需要的 RAM。
儘早刪除
如果在堆中分配了臨時對象,當不再需要它們時請將其立即刪除。如果這些臨時對象的生命長於其需要的時間,那麼該應用的 RAM 開銷往往要高於其實際所需要的。請記住,如果刪除了某個臨時對象,而指向這個對象的指標還在,那麼就需要將該指標設為NULL,以防止非法訪問或兩次刪除。
用最大資料集進行硬體測試
如果某個資料集有上限,那麼就用最大資料集來進行硬體測試。如果從來沒有對硬體進行過極限測試,很有可能會忽略某些非常慢的運算,或導致問題等。
3.3.8 分解複雜的長運算在螢幕上顯示冗長列表會對 RAM 使用形成壓力。而且,當初始化各清單控制項(如:裝置上所有連絡人的列表,或便條列表)時,其表現極差。可以編寫特別的控制項來避免這種情況,這些控制項只組裝螢幕上可見的欄目。當滾動時,釋放那些離開了螢幕區的欄目,同時添加新出現的欄目。
目標硬體上某個應用可用的堆棧比起 Windows NT 環境中模擬器可用的巨量堆棧來要小得多。結果是:在WINS模擬器中能良好啟動並執行代碼在硬體中卻不能運行,而且出現很明顯的隨機性嚴重提示( panic)。減少堆棧使用並不容易,但還是需要引起密切的關注。
正確使用描述符
有兩種類型的描述符,即堆描述符(HBufC)和棧描述符(HBufC)。所有的描述符都使用其中之一來儲存。當棧溢出時,90%時間是由棧中大型的描述符引起的。小心對待那些將導致隱含複製描述符的那些操作,並儘可能避免這種情況的出現。在某些情況下,最好分配 Hbuf C s,而不是Tbufs。某些相關的Symbian OS 類,如 Tparse,也能開銷掉許多棧空間。可以考慮使用那些耗費棧空間較少的版本(如:TParseBase)。
向描述符傳參數比傳值更好。
小心使用遞迴,在限度內產生
如果需要遞迴程式,請注意棧需求。應該努力降低向下傳遞的參數的大小,并力圖將本地自動變數移出該函數的遞迴部分。儘可能地在遞迴限制深度內產生(build)代碼,以免棧溢出。
注意登入代碼
登入代碼往往涉及到對超長描述符及將其寫入到檔案中的格式化工作。由於這一理由,它們往往成為棧溢出的原因。
盤容量降低的處理
對快閃記憶體檔案系統(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);