Java內存分配策略
java程序運行時的內存分配策略有三種,分別是靜態(tài)分配,棧式分配,堆式分配。對應的三種存儲策略使用的內存空間主要分別是靜態(tài)存儲區(qū)(方法區(qū)),棧區(qū),堆區(qū)。
靜態(tài)存儲區(qū):主要存放靜態(tài)數(shù)據(jù),全局static數(shù)據(jù)和常量。這塊內存在程序編譯時就已經分配好,并且在程序整個運行期間都存在。
棧區(qū):當方法被執(zhí)行時,方法體內的局部變量都在棧上創(chuàng)建,并在方法執(zhí)行結束時這些局部變量所持有的內存將會被自動釋放。
堆區(qū):程序運行時直接new出來的內存,這部分內存在不使用時將會由gc來負責回收。
Java四種引用
強引用:JVM 寧可拋出 OOM ,也不會讓 GC 回收具有強引用的對象;
軟引用:只有在內存空間不足時,才會被回的對象;
弱引用:在 GC 時,一旦發(fā)現(xiàn)了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存;
虛引用:任何時候都可以被GC回收
我們常說的內存泄漏是指new出來的Object無法被GC回收,即為強引用
Android常見的內存泄漏案例
一、單例造成的內存泄漏
由于單例靜態(tài)特性使得單例的生命周期和應用的生命周期一樣長。如果一個對象已經不需要使用了,而單例對象還持有該對象的引用,那么這個對象將不能被正?;厥眨瑢е铝藘却嫘孤?。如下這個典例:

這是一個普通的單例模式,當創(chuàng)建這個單例的時候,由于需要傳入一個Context,所以這個Context的生命周期的長短至關重要:
1、傳入的是Application的Context:這將沒有任何問題,因為單例的生命周期和Application的一樣長
2、傳入的是Activity的Context:當這個Context所對應的Activity退出時,由于單例對象還持有該Activity的引用,該Activity不能被正常回收。
所以正確的單例應該修改為下面這種方式:

這樣不管傳入什么Context最終將使用Application的Context,而單例的生命周期和應用的一樣長,這樣就防止了內存泄漏。
二、非靜態(tài)內部類創(chuàng)建靜態(tài)實例造成的內存泄漏
有時候我們可能會出現(xiàn)這樣的寫法

這樣就在Activity內部創(chuàng)建了一個非靜態(tài)內部類的單例,每次啟動Activity時都會使用該單例的數(shù)據(jù),這樣雖然避免了資源的重復創(chuàng)建,不過這種寫法卻會造成內存泄漏,因為非靜態(tài)內部類默認會持有外部類的引用,而又使用了該非靜態(tài)內部類創(chuàng)建了一個靜態(tài)的實例,該實例的生命周期和應用的一樣長,這就導致了該靜態(tài)實例一直會持有該Activity的引用,導致Activity的內存資源不能正常回收。
正確的做法為:將該內部類設為靜態(tài)內部類或將該內部類抽取出來封裝成一個單例,如果需要使用Context,使用ApplicationContext
三、Handler造成的內存泄漏
Handler的使用造成的內存泄漏問題應該說最為常見了,平時在處理網(wǎng)絡任務或者封裝一些請求回調等api都應該會借助Handler來處理,對于Handler的使用代碼編寫一不規(guī)范即有可能造成內存泄漏,如下示例:

這種創(chuàng)建Handler的方式會造成內存泄漏,由于mHandler是Handler的非靜態(tài)匿名內部類的實例,所以它持有外部類Activity的引用,而消息隊列是在一個Looper線程中不斷輪詢處理消息,那么當這個Activity退出時消息隊列中還有未處理的消息或者正在處理消息,而消息隊列中的Message持有mHandler實例的引用,mHandler又持有Activity的引用,所以導致該Activity的內存資源無法及時回收,引發(fā)內存泄漏,所以另外一種做法為:

創(chuàng)建一個靜態(tài)Handler內部類,然后對Handler持有的對象使用弱引用,這樣在回收時就可以回收Handler持有的對象,這樣雖然避免了Activity泄漏,不過Looper線程的消息隊列中還是可能會有待處理的消息,所以我們在Activity的Destroy時或者Stop時應該移除消息隊列中的消息

使用mHandler.removeCallbacksAndMessages(null);是移除消息隊列中所有消息和所有的Runnable。
四、資源未關閉造成的內存泄漏
對于使用了BraodcastReceiver,ContentObserver,F(xiàn)ile,Cursor,Stream,Bitmap等資源的使用,應該在Activity銷毀時及時關閉或者注銷,否則這些資源將不會被回收,造成內存泄漏。
10 條提升 Android 性能的建議
https://academy.realm.io/cn/posts/droidcon-farber-improving-android-app-performance/