Android內(nèi)存泄漏實例分析

昨天被問到一個內(nèi)存泄漏問題,正好近期在錄制性能優(yōu)化相關(guān)的課程,用我講的方法來分析問題??

有時候內(nèi)存泄漏真是措不及防,潛伏的很深,不用工具的話壓根感知不到,往往只有在錯誤日志里才看得到,不過那個時候也已經(jīng)晚了。

先上個LeakCanary的warning圖

Paste_Image.png

從圖上來看,很直觀,MainActivity泄漏了,持有的是MyLinkMovementMethod,還是個static變量。

這么看起來很容易解嘛,在MyLinkMovementMethod里把context引用去掉不就好了么,有什么好問的。

然而看了代碼,我也有點懵逼,大家也來瞅瞅。

Paste_Image.png

這個MyLinkMovementMethod類中只有一個成員變量TouchableSpan,并沒有持有context呀,我被誤導(dǎo)的去翻了它的父類LinkMovementMethod,發(fā)現(xiàn)并沒有任何成員變量。那這個鍋只能是TouchableSpan來背了。

說來也是詭異的很,當(dāng)我要TouchableSpan類的截圖時,對方給我的是這樣的:

Paste_Image.png

wtf, 這span沒有持有context呀,為什么會泄漏?這不科學(xué)。onClick(View)也沒有泄漏的可能。于是我又讓對方發(fā)TouchableSpan類給我

Paste_Image.png

好吧,我也不知道問題出在哪了,被對方牽著走了一路,沒線索了。后來他一直在糾結(jié)widget.getContext().startActivity(intent)要不要換成applicationContext,這又是另外一個故事了。。。不管用什么context,這里都不存在泄漏。

最后沒轍,好歹我也擼了相關(guān)課程,連個內(nèi)存泄漏的原因都找不到,我不甘心啊。。

于是我讓他把相關(guān)代碼都發(fā)給我。。??戳舜a內(nèi)心都是崩潰的

Paste_Image.png

內(nèi)部類。。。內(nèi)部類。。。非靜態(tài)內(nèi)部類能持有外部的引用啊。心塞。

我們再把整個泄漏的過程梳理下。

Paste_Image.png

需求是textview能局部點擊,整體的onClick事件無法滿足,所以需要ClickableSpan來標(biāo)記。

于是自定義一個TagTextView,在TagTextView中有個內(nèi)部類Span來監(jiān)聽局部點擊,但Span是如何知道自己被點擊的呢?用MyLinkMovementMethod來處理textview的onTouch事件。解決方案是對的,但是代碼寫的有點渣。

MyLinkMovementMethod為單例,TouchableSpan一旦被實例化出來,除非手動置為null,否則不會釋放,而由于它是TagTextView的內(nèi)部類,所以持有這個TextView的引用,TextView是被MainActivity創(chuàng)建出來的,最終導(dǎo)致MainActivity無法被回收。

MyLinkMovementMethod->TagTextView.TouchableSpan->TagTextView->MainActivity

現(xiàn)在再來看LeakCanary的warning

Paste_Image.png

剛好能對應(yīng)上了吧,有個工具能幫你做分析挺好的,不然review代碼都不一定能找出來。

至于怎么解決?方法倒是很簡單的:

  1. TagTextView.Span變?yōu)閟tatic,靜態(tài)內(nèi)部類不持有外部類的引用,就像Handler要用static一樣。
  2. MyLinkMovementMethod中不能有Span這個成員變量,讓Span引用只存在于某個方法的作用域中。
  3. 當(dāng)TagTextView的TouchEvent為UP時,應(yīng)手動將Span置為null。

這算是一個比較有代表性的內(nèi)存泄漏了,如果你對內(nèi)存泄漏的概念與成因還不夠熟悉,可以參考Stay錄制的性能優(yōu)化合輯,從java角度去講內(nèi)存泄漏你肯定能看懂。

另外有一點需要改進的,tag的點擊事件應(yīng)該傳遞到外部去,不應(yīng)該由Span自己處理跳轉(zhuǎn)到另外一個activity中去,這不符合設(shè)計原則,如果某個Tag跳轉(zhuǎn)的activity不是固定的怎么辦呢?自定義View的職責(zé)應(yīng)該是單一的,只負(fù)責(zé)接收事件,解析事件,具體的解決事件應(yīng)該由上層來處理,不然就沒法復(fù)用了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 Java 中的內(nèi)存分配 靜態(tài)儲存區(qū):編譯時就分配好,在程序整個運行期間都存在。它主要存放靜態(tài)數(shù)據(jù)和常量; 棧...
    wangling90閱讀 854評論 0 0
  • 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏大家都不陌生了,簡單粗俗的講,...
    宇宙只有巴掌大閱讀 2,493評論 0 12
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏...
    _痞子閱讀 1,703評論 0 8
  • 由于項目中大量出現(xiàn)內(nèi)存泄漏導(dǎo)致內(nèi)存使用量增多而不能立馬釋放,不得不研究內(nèi)存泄漏,接下來我們切入主題。以下都是本人收...
    WuXiao_閱讀 3,301評論 2 12
  • Android 內(nèi)存泄漏總結(jié) 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應(yīng)用出現(xiàn)內(nèi)存泄漏的問題。內(nèi)存泄漏...
    apkcore閱讀 1,310評論 2 7

友情鏈接更多精彩內(nèi)容