首先參考一下Google I/O Garbage Collection圖片
圖片中有黃色及藍色的區塊
可以理解為有爸媽的孩子及孤兒吧
孤兒的部分,由於來歷已不可考所以Garbage Collection並沒有辦法處理它
像這類狀況常在開發時因為不容易立即造成當機而被忽略,我本人就是這樣,幾乎都沒有在處理這樣的狀況
但是當產品規模漸漸變大,孤兒越來越多,會造成被佔用並且無法被回收的記憶體越來越多,而導致OOM
所以必須從平時就養成好習慣別讓孤兒產生
這樣說起來可能有點抽象,所以就來實做一個練習吧
開始之前要介紹一下我使用的工具
再爬了一些文之後發先這玩意兒滿好用的,也很清楚推薦給大家除錯的時候可以用
https://github.com/square/leakcanary
按照平常的習慣用Singleton的方式建置了一個呼叫API的物件,並且在Activity使用
依照先前的壞習慣,程式寫到這就結束了
這時候按下Back離開Activity(onDestroy被呼叫)
在有安裝leakcanary情況下,馬上就被偵測到問題
也可以很明確的從Stack中看到是錯在什麼地方
這邊用Google I/O的圖解釋一下
onCreate Activity時reference狀態如下(都是黃色的)
MainActivty -> ApiRequest instance -> context
onDestroy Activity時ApiRequest instance中的context瞬間變孤兒
(MainActivty -> ApiRequest instance) x context
我想主要的原因是Activity本身就有回收機制,所以在onCreate初始化的ApiRequest也可以直接被回收機制處理掉
但是在ApiRequest中的物件大概就沒這麼幸運了
先在ApiRequest物件中加上一個可以配合Activity onDestroy lifecycle的方法
在這方法中處理掉會造成Memory leak的問題
並且在Activity onDestroy時呼叫這個方法
再進行一次測試leakcanary就不再會報出這樣的問題
有寫錯的地方歡迎指正討論喔
Singleton 通常是給 multi Thread/ multi Object 共用1個 object/resource.
你的 getInstance 沒有Thread safe, 有機會重覆 create ApiRequest.
另外你 destory 了 context, 但 getinstance 沒有更新 context, 之後會有 error.
不過你带出了 class 的 static value 如果沒處理好, 是有機會memory leak.
了解 非常感謝你提出的建議 我會再實作測試你講的狀況 有機會再分享出來討論