Android性能優化以內存篇

性能優化一直是高級Android工程師必問的,這也每每涉及到對Java、JVM、Android運行機制、監控工具使用等全方位的知識點,是很好的面試方向。面試

本篇會圍繞Android與Java的性能優化專項之內存展開並深刻。數據庫

內存是Android運行性能相當重要的一項指標,每一個進程能使用的內存是有限的。不合理的使用內存會致使頻繁的GC、甚至發生OOM,過多GC會致使App卡頓,而內存泄漏或者內存抖動均可以致使OOM,這是沒法接受的。緩存

所以,對於一個合格的高級Android工程師,必須保持對內存的高度敏感性,本文會針對內存提出一系列性能優化手段。性能優化

何時會致使頻繁GC

  1. 內存抖動
    短期內建立了大量對象同時又被快速釋放。好比在一個大循環裏去不斷建立對象,會致使頻繁gc;
  2. 內存泄漏
    內存泄漏會致使可用內存逐漸變少,並且內存碎片加多,這也會增多gc次數,甚至可能發生OOM
  3. 一次申請太大內存空間
    因爲內存碎片的存在,就算內存自己足夠,但因爲碎片致使沒法找到一塊大空間,這也會觸發gc;

內存優化準則

1. 能不建立的對象就不建立

好比字符串拼接,能夠手動使用StringBuilder,而不是使用"+","+"被編譯器優化後會每次建立StringBuilder對象,形成浪費;函數

並且,尤爲注意在主線程裏不要過多建立對象。由於在GC時會鎖住堆內存,此時請求分配的線程也會被掛起,這顯然會致使主線程的卡頓。因此在一些主線程高頻函數,如onDraw,onTouchEvent裏不要去建立對象。工具

2. 儘量複用已經建立的對象

仍是StringBuilder的例子,基於一個StringBuilder能夠經過SetLength(0)支持不少次的字符串拼接。性能

多使用系統提供的對象池,好比線程池,Long、Integer、Short等包類型裏的緩存值(經過valueOf取),列表view的複用等優化

3. 防止內存泄漏

內存一旦發生泄漏,意味着堆裏有一塊區域持續被再也不使用的變量佔據,這天然會致使可用內存減小而發生gc,甚至OOM。ui

通常內存泄漏有幾下幾種狀況:線程

I. 長生命週期持有短生命週期引用,如Activity泄漏

通常是長生命週期的變量持有Activity引用,致使在gc時沒法標記Activity從而沒法回收,而Activity自己通常會引用到很是多的資源如View, Image,則這些大塊資源均沒法回收。

這種時候,咱們能夠用WeakReference來弱引用;針對Activity這種場景可使用LeakCanary來進行監控,它會在Activity onDestroy後監控其引用是否被釋放,若未釋放則主動觸發一次gc,gc後若是仍未釋放,則會通知開發者。

II. 靜態變量和單例濫用

靜態變量通常是在裝載類裏的連接時進行內存分配,初始化時進行賦值。關鍵是,靜態變量會伴隨Android進程整個生命週期,若是引用了某塊堆內存,則該內存沒法被回收。單例也是相似。咱們在開發中不該該依賴太多靜態變量和單例。

III. finalize來兜底

對於一些較大內存的對象,能夠考慮利用finalize方法,防止在忘記釋放時主動進行一些清理工做。像SQLiteDatabase、FileInputStream等都會在finalize方法裏面進行一些清理工做,如關閉數據庫。

不過,finalize方法並非萬能的,它也會致使其餘問題,後續再說。

IV. 合理應用Java各類引用

Java裏提供了四種引用:

  • 強引用StrongReference:這種引用的對象不會被GC回收,在堆裏存活時間最久;
  • 弱引用WeakReference:在GC時一旦遇到WeakReference,不管堆內存空間是否足夠都會進行回收,不過考慮到GC線程優先級很低,因此WeakReference能存活較長時間;(附:當WeakReference對象被回收後,它自身可被放入一個ReferenceQueue裏,LeakCanary裏便應用了這個特性來檢測Activity是否已被回收)
  • 軟引用SoftReference:當堆內存不足時,會對SoftReference進行回收,它存活的時間通常長於WeakReference。(附:SoftReference是在第三次內存分配失敗時進行回收。流程:第一次分配失敗->GC->第二次分配失敗->擴容->第三次仍分配失敗->清理SoftReference)
  • 虛引用PhantomReference:等於沒有引用,隨時隨地都會被回收
相關文章
相關標籤/搜索