@Synchronized override fun expectWeaklyReachable(
watchedObject: Any,
description: String
) {
if (!isEnabled()) {
return
}
removeWeaklyReachableObjects()
val key = UUID.randomUUID()
.toString()
val watchUptimeMillis = clock.uptimeMillis()
val reference =
KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
SharkLog.d {
"Watching " +
(if (watchedObject is Class<*>) watchedObject.toString() else “instance of ${watchedObject.javaClass.name}”) +
(if (description.isNotEmpty()) " ($description)" else “”) +
" with key $key"
}
watchedObjects[key] = reference
checkRetainedExecutor.execute {
moveToRetained(key)
}
}
上述代碼的主要邏輯是:
-
移除弱可達的對象
-
將當前的
watchedObject
添加到KeyedWeakReference
當中 -
將這個weakReference保存到數(shù)組中
-
在
checkRetainedExecutor
中執(zhí)行moveToRetained
方法
根據(jù)removeWeaklyReachableObjects
方法中原理,如果這個對象除了由ObjectWatcher
所添加的WeakReference以外,沒有其他對象在引用它了,那么這個對象也就可以回收了,watchedObjects
也就可以移除他了。
private fun removeWeaklyReachableObjects() {
var ref: KeyedWeakReference?
do {
ref = queue.poll() as KeyedWeakReference?
if (ref != null) {
watchedObjects.remove(ref.key)
}
} while (ref != null)
}
}
checkRetainedExecutor
其實是個單例對象,里面會通過handler來延遲5s
來執(zhí)行方法。如果超過5s
則會觸發(fā)LeakCanary
的泄漏檢測機制。5s
只是個經(jīng)驗值應該,因為GC并不是實時發(fā)生,因而預留5s
交給GC操作。
觸發(fā)了LeakCanary的泄漏檢測之后,則會執(zhí)行HeapDumpTrigger
的dumpHeap
方法,在獲取到了.hprof
文件之后,調(diào)用HeapAnalyzerService.runAnalysis()
給出分析結(jié)果。 關(guān)于.hprof
文件的分析,不是本文重點,具體可以參考hprof文件協(xié)議。其分析基本也就是根據(jù)GC Root去尋找泄漏的對象,大體流程圖如下。
在Android中常見的內(nèi)存泄漏
單例
單例所導致的內(nèi)存泄漏幾乎是在android開發(fā)中最為常見的內(nèi)存泄漏問題了。
public class Singleton {
private static Singleton singleton;
private Context context;
private Singleton(Context context) {
this.context = context;
}
public static Singleton getInstance(Context context) {
if (singleton == null) {
singleton = new Singleton(context);
}
return singleton;
}
}
在上面的代碼中,如果在執(zhí)行getInstance
方法的時候,傳入的是activity的對象,那么該activity對象就沒法被及時回收,導致內(nèi)存泄漏,可以考慮傳入ApplicationContext,或者把context放入到方法變量中。
非靜態(tài)內(nèi)部類(包括匿名內(nèi)部類)
非靜態(tài)內(nèi)部類會默認持有外部類的引用,如果它的生命周期長于外部類時,就會導致內(nèi)存泄漏。 在android開發(fā),這種情況常常見于Handler的使用。
盡可能避免使用靜態(tài)變量
class MainActivity : AppCompatActivity() {
companion object {
@JvmStatic
private var info: StaticInfo? = null
}
override fun onCreate(savedInstanceState: Bundle?) {
info = StaticInfo(this)
}
class StaticInfo(activity: MainActivity) {
}
在上述代碼中,info
是一個靜態(tài)變量,但是它持有了activity
的引用,由于靜態(tài)變量的生命周期要比activity
的生命周期長,導致activity
無法及時回收,造成內(nèi)存泄漏。
資源未關(guān)閉造成的內(nèi)存泄漏
諸如cursor、inputStream等對象一定要注意及時關(guān)閉
try {
}catch (e:Exception) {
}finally {
// 可以在finally方法里把cursor等對象進行關(guān)閉
}
集合中的對象未及時清理造成的內(nèi)存泄漏
val list = ArrayList()
例如,如果一個list中存放的是activity對象,就會可能導致activity無法及時回收。如果該list是靜態(tài)對象的話,不及時移除activity的話,就更會產(chǎn)生內(nèi)存泄漏了。
webview造成的內(nèi)存泄漏
因為webview在加載完網(wǎng)頁后,它的callback會持有activity的引用,造成webview的內(nèi)存無法釋放??梢栽赼ctivity的onDestroy()方法中移除該webview,并調(diào)用webview.destroy()。
未取消注冊或回調(diào)造成的內(nèi)存泄漏
在android中回調(diào)是使用非常多的,但如果在注冊回調(diào)的時候,傳入了context對象,則需要注 意及時取消回調(diào),否則就可能會出現(xiàn)內(nèi)存泄漏。例如eventbus和廣播。
內(nèi)存優(yōu)化
-
使用
intentService
代替Service
,或者service執(zhí)行完記得及時停止 -
在系統(tǒng)資源緊張的時候,盡可能多釋放一些非重要的資源(如圖片的內(nèi)存緩存)
class MyApp : Application() {
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
// 可以在這里做些內(nèi)存釋放的工作
}
}
- 避免
bitmap
的濫用
如果不是必須操作bitmap,對于圖片加載,我們可以使用一些優(yōu)秀的第三方庫來進行加載。使用bitmap記得復用和及時回收。
- 使用針對內(nèi)存優(yōu)化過的數(shù)據(jù)容器
在大多數(shù)場景下,可以使用SparseArray代替HashMap等可以一定程度上減少內(nèi)存使用。
- 使用多進程
自我介紹一下,小編13年上海交大畢業(yè),曾經(jīng)在小公司待過,也去過華為、OPPO等大廠,18年進入阿里一直到現(xiàn)在。
深知大多數(shù)初中級安卓工程師,想要提升技能,往往是自己摸索成長,但自己不成體系的自學效果低效又漫長,而且極易碰到天花板技術(shù)停滯不前!
因此收集整理了一份《2024年最新Android移動開發(fā)全套學習資料》送給大家,初衷也很簡單,就是希望能夠幫助到想自學提升又不知道該從何學起的朋友,同時減輕大家的負擔。
由于文件比較大,這里只是將部分目錄截圖出來,每個節(jié)點里面都包含大廠面經(jīng)、學習筆記、源碼講義、實戰(zhàn)項目、講解視頻
如果你覺得這些內(nèi)容對你有幫助,可以添加下面V無償領?。。▊渥ndroid)
總結(jié)
首先是感覺自己的基礎還是不夠吧,大廠好像都喜歡問這些底層原理。
另外一部分原因在于資料也還沒有看完,一面時憑借那份資料考前突擊惡補個幾天居然也能輕松應對(在這里還是要感謝那份資料,真的牛),于是自我感覺良好,資料就沒有怎么深究下去了。
之前的準備只涉及了Java、Android、計網(wǎng)、數(shù)據(jù)結(jié)構(gòu)與算法這些方面,面對面試官對其他基礎課程的考察顯得捉襟見肘。
下一步還是要查漏補缺,進行針對性復習。
最后的最后,那套資料這次一定要全部看完,是真的太全面了,各個知識點都涵蓋了,幾乎我面試遇到的所有問題的知識點這里面都有!在這里也免費分享給大家,希望大家不要犯和我一樣的錯誤呀?。?!一定要看完!
獲取方式:點擊我的GitHub
d、計網(wǎng)、數(shù)據(jù)結(jié)構(gòu)與算法這些方面,面對面試官對其他基礎課程的考察顯得捉襟見肘。
下一步還是要查漏補缺,進行針對性復習。
最后的最后,那套資料這次一定要全部看完,是真的太全面了,各個知識點都涵蓋了,幾乎我面試遇到的所有問題的知識點這里面都有!在這里也免費分享給大家,希望大家不要犯和我一樣的錯誤呀?。。∫欢ㄒ赐?!
[外鏈圖片轉(zhuǎn)存中…(img-xIPHanw0-1711046455617)]
[外鏈圖片轉(zhuǎn)存中…(img-r5jSmCJT-1711046455617)]文章來源:http://www.zghlxwxcb.cn/news/detail-857767.html
[外鏈圖片轉(zhuǎn)存中…(img-58xIsvt7-1711046455618)]
獲取方式:點擊我的GitHub文章來源地址http://www.zghlxwxcb.cn/news/detail-857767.html
到了這里,關(guān)于Android內(nèi)存泄漏分析及檢測工具LeakCanary簡介,Android進階的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!