Android優化三:內存泄漏

Android優化一:提綱
Android優化二:性能檢測
Android優化三:內存優化
Android優化四:App啟動速度優化
Android優化五:布局優化
Android優化六:性能優化

什么是內存泄漏?

根據 Java 內存回收機制的“可達性分析法”,如果這些對象是可達的,但是這些對象是無用的,就會導致內存泄漏,內存泄漏的積累最終導致內存溢出。

分類

Android中內存溢出主要分為四類:

①集合類泄漏
②單例/靜態變量造成的內存泄漏
③匿名內部類/非靜態內部類
④資源未關閉造成的內存泄漏

Q:單例為什么會導致內存泄漏?

其實單例本身跟內存泄漏是沒什么關系的,只有在單例使用不恰單才會導致內存泄漏。
單例導致內存泄漏主要的原因是:單例的靜態特性使得單例的生命周期跟整個應用的生命周期一樣長。
如果我們在單例中傳入的 Context 是 Activity 的 context,當這個 Context 所對應的 Activity 退出時,由于該 Context 的引用被單例對象所持有,其生命周期等于整個應用程序的生命周期,所以當前 Activity 退出時它的內存并不會被回收,這就造成泄漏了。
同理被 static 修飾的成員變量也是如此,其生命周期將與整個app進程生命周期一樣。

Q:handler 和非靜態內部類為什么會導致內存泄漏?

非靜態內部類默認會持有外部類的引用,handler 的生命周期與 Activity 的生命周期不一致,
如果 Activity 銷毀了但是 Handler 里面有未處理完的延時消息,導致 Activity 不能被 GC 回收。

OOM異常

  • 可以通過getMemoryClass( )來獲取App的可用堆內存,如果申請的內存超過這個值,就會造成OOM異常。
  • 可以在AndroidManifest.xml文件<applicatiion>中可以設置 android:largeHeap="true"活的更大的堆內存。

具體細節

1、Bitmap圖片過大

解決辦法:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;

圖片寬高都為原來的二分之一,即圖片為原來的四分之一。

  • bitmap.get().recycle();
    在用完Bitmap時,要及時的recycle掉。recycle并不能確定立即就會將Bitmap釋放掉,但是會給虛擬機一個暗示:“該圖片可以釋放了”。

  • 軟引用(SoftRefrence)
    我們使用Bitmap后沒有保留對它的引用,因此就無法調用Recycle函數。這時候巧妙的運用軟引用,可以使Bitmap在內存快不足時得到有效的釋放 。

但是是現在已經不再推薦使用這種方式了,因為從 Android 2.3 (API Level 9)開始,垃圾回收器會更傾向于回收持有軟引用或弱引用的對象,這讓軟引用和弱引用變得不再可靠。另外,Android 3.0 (API Level 11)中,圖片的數據會存儲在本地的內存當中,因而無法用一種可預見的方式將其釋放,這就有潛在的風險造成應用程序的內存溢出并崩潰。
From 郭霖的博客

  • 建議使用成熟的Glide、Picasso、Fresco框架來加載圖片。

2、界面切換

  • 看頁面布局有沒有大的圖片,比如背景圖之類的。
  • 直接把XML配置成view再放到一個容器里面,避免重復加載。
  • 在頁面切換時盡可能少地重復使用一些代碼。

3、資源未關閉

  • BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源的使用沒有注銷導致。
  • 在Activity銷毀時及時關閉或者注銷。

4、ListView沒有使用緩存

  • 使用的convertView進行緩存
  • 建議使用5.0出來的RecycleView替代Listview。

5、Handler導致

  • 應該申明為靜態對象, 并在其內部類中保存一個對外部類的弱引用。
  • 在Activity銷毀時及時關閉或者注銷
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //handler導致內存泄漏;
        //當Activity銷毀時,匿名內部類一直持有Activity的引用,無法釋放。
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //執行邏輯
            }
        }, 10000L);
    }

6、 線程導致

  • 線程產生內存泄露的主要原因在于線程生命周期的不可控。
  • 將線程的內部類,改為靜態內部類。
  • 采用線程池, 避免程序中存在大量的Thread。

7、盡量使用9path圖片

.9圖片可以任意調整大小,進行拉伸。

8、使用單例造成

  • 當調用getInstance時,如果傳入的context是Activity的context。只要這個單例沒有被釋放,那么這個Activity也不會被釋放一直到進程退出才會釋放。
  • 使用Application的Context。

9、非靜態內部類創建靜態實例

  • 將非靜態內部類修改為靜態內部類。(靜態內部類不會隱式持有外部類)
  • Context盡量使用Application Context,因為Application的Context的生命周期比較長。

10、使用了靜態的Activity和View

  • private static View sView;
  • 應該及時將靜態的應用 置為null,而且一般不建議將View及Activity設置為靜態。

11、屬性動畫導致的內存泄漏

  • 屬性動畫有一類無限循環的動畫, 如果在Activity中播放此類動畫且沒有在Activity退出的時候沒有停止動畫. 盡管無法界面上看到效果, 但是創建這個動畫所關聯的View被動畫所持有, 而View又持有了Activity, 最終Activity無法釋放.
  • 解決方案是在onDestroy()中調用動畫的cancel()來停止動畫.

12、幀動畫導致

  • 幀動畫使用的圖片過大過多導致

終極大招:LeakCanary

LeakCanary 是一個開源的在debug版本中檢測內存泄漏的java庫。
LeakCanary 中文使用說明
平時寫代碼稍微注意點,再用這個檢測基本能搞定所有oom異常。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,637評論 25 708
  • 性能優化系列閱讀 Android性能優化 性能優化 - 消除卡頓 性能優化- 內存優化 性能分析工具 - Trac...
    JackChen1024閱讀 1,332評論 1 20
  • HereAndroid的內存優化是性能優化中很重要的一部分,而避免OOM又是內存優化中比較核心的一點。這是一篇關于...
    HarryXR閱讀 3,832評論 1 24
  • 李堤 河南自古稱中原, 中原之中有汝南。 汝南城北二十里, 古村李堤是故園。 書名李堤知家少, 俗名”勒滴”傳...
    南海老人閱讀 263評論 1 4
  • 此刻,八點四十九分,我戴著耳機在屬于自己的空間里隨機播放著德永英明的音樂。有一種感覺已經牽絆很久了,身處在這個被縱...
    Hosn閱讀 435評論 1 3