Android性能優化學習與實踐小結

前言

本文主要是本人這大約一週的時間在項目中進行性能優化的學習與實踐筆記,對於性能優化方面有許多優秀的文章。文中大量引用了其他文章的描述,以及根據自己的理解整理成文,主要是主要從內存和流暢度兩方面出發,對這部分工作的一個小結。老大一直強調性能優化方面的工作,但是一直沒有做。這段產品正在重新規劃,終於來做一做性能優化的工作。再次閱讀了張總的Android應用開發進階必經之路之性能優化,以及胡凱的Android性能優化典範,TMQ團隊的《移動App性能評測與優化》,從中收穫良多,在此真心感謝前輩們的分享。

一、內存

內存,對於APP而言,是一項非常珍貴的資源,我們必須要合理的“借用”,爲何說是借用 ?我想這是我自己的一點理解。古語有云:有借有還,再借不難,所以當你申請了內存,那就得記得適時釋放出來。當然,如果,你如果又借給了別人,那麼也要告訴別人要記得還,不然就很可能 泄漏了 。總之,內存是借來的,要記得還。

1、內存抖動

  • 原因:頻繁的創建對象,並快速釋放該對象,導致JVM頻繁的GC;
  • 現象:AS的Monitor觀察內存,明顯的鋸齒狀,頻繁的漲跌;通過Allocation Tracker 查看短時間內,同一個棧不斷進出的相同對象。
  • 分析:
    • for循環中分配對象;
    • 自定義onDraw中創建對象;
  • 解決:儘量避免上述情況,若實在無法避免,可以考慮採用對象池模型來處理;

2、內存泄漏

  • 概念:程序中不再使用的對象無法被GC識別,一直佔用內存空間無法被釋放掉。機器內存剩餘空間減少,一方面需要申請更多的內存浪費資源,另一方面頻繁的GC引發的性能問題;
  • 常見問題
    • 自定義的View中set了listener等回調接口,沒有主動釋放;
    • 自定義的Layout中set進了外部的某些view,沒有主動釋放;
    • 初始化了第三方庫,如volley,但是沒有主動釋放;
    • 從activity中將actvity中的對象set進了包含的fragment,fragment的持有了該對象,fragment在destroy時沒有主動釋放;
    • 非靜態內部類導致的內存泄漏,如Hanlder,可以將內部類寫成靜態的,並使用弱引用的方式;
    • IO操作,使用完後記得關閉stream之類;
    • 自定義View中存在TypeArray,使用完之後沒有關閉;
    • 四大組件的context;
  • 查找辦法
    • AS的Memory Usage獲取內存使用情況;
    • AS獲取內存快照分析內存,找到沒有釋放的對象,分析修改,驗證;
  • 如何避免

    • 減少內存使用
      • 輕量級數據結構,如HashMap
      • 減少Bitmap佔用內存,縮放比例,修改解碼格式;
      • 使用更小的圖片
    • 內存重複使用
      • 系統自帶的資源,如color、layout\string等
      • ListView,GridView等的itemView複用;
      • Bitmap對象複用;
      • StringBuilder字符串拼接;
  • 關鍵點:除了使用一些方法去檢查修復,我們應該有個良好的內存管理意識,儘管JVM有自動的內存管理機制,但是由於我們書寫了不合理的代碼,到時無法GC。所以學會合理管理內存、節約資源也很重要。

二、流暢度

流暢度是用戶體驗中很重要的一部分,逼近用戶的耐心很有限,就我個人而言。如果一個應用卡的要死,絕逼先卸載,也許永遠不會再用啦。簡單點說,就是應用在切換、渲染界面給人感覺舒不舒服,是不是有卡頓現象。我們通常通過FPS這一指標來評判,但是在《移動APP性能評測與優化》一書中提出FPS這一指標並不準備,所以提出了SM的概念。下面是流暢度優化的幾個方面:

1、過渡繪製

這個沒有什麼可說的,在系統設置中打開調試,就可以觀察到現象。根據不同個顏色來判斷是否過渡繪製,網上的教程很多。出現過渡繪製主要是由於View的backgroud重複繪製。首先Window本身就有自己的background,如果要自定義自己的background,得記得把window的background設爲null。

2、佈局優化

  • 層級越深,佈局越複雜,計算、測量等越耗時,就有可能造成丟幀現象,造成卡頓的概率就越高;
  • 相對RelativeLayout而言,優選選擇LinearLayout;
  • 可複用的組件抽取出來,使用include標籤導入;
  • 不常用的標籤用ViewStub;
  • 使用merge標籤減少佈局的嵌套層次;
  • 在LinearLayout佈局中layout_weight屬性很耗性能;
  • ListView中的item_view儘量簡單,在GetView方法中儘量減少邏輯運算;

3、解放UI線程

顧名思義,我們把一些耗時操作放到子線程中去完成,我們也可以通過打開嚴苛模式來預防。同時,自定義View的OnDraw方法中儘量減少new對象操作,緩存策略,預加載機制也是我們可以考慮的。

三、分析工具以及使用

本人基本僅藉助於AndroidStudio自帶的工具和系統設置自帶調試工具進行分析以及優化工作;

  • 靜態檢查:AndroidStudio執行Lint檢查操作後,在檢查結果Android>Lint>Performance中有許多與性能相關的選項,謹慎修改優化。

  • Monitors:可以直觀個查看內存、CPU、GPU、網絡情況;

  • [Allocation Tracking]:(http://blog.csdn.net/itfootball/article/details/48750849):這個可以追蹤某一過程中內存分配的情況,在查看內存抖動(漲跌變動大的時候);

  • [Heap Snapshot]:(http://www.cnblogs.com/linguanh/p/5601232.html):內存泄漏檢測分析,我們可以通過手動GC然後獲取內存快照來分析,找出造成泄漏的原因;配合Memory Usage來驗證自己是否修改正確。
  • Method Tracing: 這個可以分析方法執行耗時、調用次數,點擊CPU旁邊的那個鬧鐘樣子的按鈕開始或者結束記錄,可以分析某些耗時方法,來優化流暢度的問題。
  • 系統設置:OverDraw 查找過度繪製問題;
  • 系統設置:GPU呈現模式分析查看UI渲染、分析流暢度問題;

四、個人體會

在性能優化方面,一直研究不深。至今爲止,也只是在很淺的層面上藉助於工具來進行優化,也順便了解了部分底層的一些知識。作爲一名APP應用開發者,我們的目標不僅只是實現某一個功能,還要關注這個應用是否好用。在內存消耗、體驗是否流暢、apk的體積大小等各方面,都直接影響了app的最終質量。其實說到底,性能體驗不好,最終的原因還是程序的設計不合理,代碼寫的不規範,佈局不合理等等原因造成的。所以,進行性能優化的工作,不僅提高了應用app的性能,同時也是幫助自己寫出更優秀的代碼。我們可能不能夠想測試工程師那樣去深入研究,但是主動防禦相比起反攻而言,同樣有很大的價值。

五、參考文獻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章