iT邦幫忙

1

Android Memory Leak及衍伸問題01

首先參考一下Google I/O Garbage Collection圖片
圖片中有黃色及藍色的區塊
可以理解為有爸媽的孩子及孤兒吧
孤兒的部分,由於來歷已不可考所以Garbage Collection並沒有辦法處理它
https://ithelp.ithome.com.tw/upload/images/20200514/20126774o7mHYHuZh0.png

像這類狀況常在開發時因為不容易立即造成當機而被忽略,我本人就是這樣,幾乎都沒有在處理這樣的狀況
但是當產品規模漸漸變大,孤兒越來越多,會造成被佔用並且無法被回收的記憶體越來越多,而導致OOM
所以必須從平時就養成好習慣別讓孤兒產生

這樣說起來可能有點抽象,所以就來實做一個練習吧
開始之前要介紹一下我使用的工具
再爬了一些文之後發先這玩意兒滿好用的,也很清楚推薦給大家除錯的時候可以用
https://github.com/square/leakcanary

練習題

錯誤版

按照平常的習慣用Singleton的方式建置了一個呼叫API的物件,並且在Activity使用
https://ithelp.ithome.com.tw/upload/images/20200515/20126774F0uLi6XW8P.png
https://ithelp.ithome.com.tw/upload/images/20200515/20126774rc7PCAA9vd.png
依照先前的壞習慣,程式寫到這就結束了
這時候按下Back離開Activity(onDestroy被呼叫)

在有安裝leakcanary情況下,馬上就被偵測到問題
也可以很明確的從Stack中看到是錯在什麼地方
https://ithelp.ithome.com.tw/upload/images/20200515/20126774xzs5TSWdoD.jpg

這邊用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的問題
https://ithelp.ithome.com.tw/upload/images/20200515/20126774jrTJaWW2yS.png

並且在Activity onDestroy時呼叫這個方法
https://ithelp.ithome.com.tw/upload/images/20200515/201267748nKjj3CBQs.png

再進行一次測試leakcanary就不再會報出這樣的問題

有寫錯的地方歡迎指正討論喔


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
ffchung
iT邦新手 5 級 ‧ 2020-05-15 16:10:48

Singleton 通常是給 multi Thread/ multi Object 共用1個 object/resource.

你的 getInstance 沒有Thread safe, 有機會重覆 create ApiRequest.

另外你 destory 了 context, 但 getinstance 沒有更新 context, 之後會有 error.

不過你带出了 class 的 static value 如果沒處理好, 是有機會memory leak.

MarcusLiu iT邦新手 5 級 ‧ 2020-05-16 00:11:12 檢舉

了解 非常感謝你提出的建議 我會再實作測試你講的狀況 有機會再分享出來討論

我要留言

立即登入留言