android内存泄漏原因分析,Android Studio3.6的内存泄漏检测功能 VS LeakCanary
2020年2月,谷歌發布了Android Studio 3.6版。它包括一個新的“內存泄漏檢測”功能。這是否意味著我們不再需要流行的內存泄漏檢測庫“Leak Canary”了?在過去的幾天里,我花了一些時間來研究android studio的新特性,希望在這里分享我的發現和想法。
內存泄露示例程序
我創建了一個示例應用程序,其中包含一個名為LeakingActivity的活動。顧名思義,此活動演示了導致泄漏的常見原因。它將偵聽器定義為內部類,并將該偵聽器注冊到具有較長生命周期的對象。在我們的例子中,這個對象是一個單例,它的壽命與應用程序的壽命一樣長。由于我們在離開活動時沒有注銷偵聽器,所以即使在Android框架調用onDestroy()方法之后,Singleton仍然保留對它的引用。偵聽器是活動的內部類,因此對活動有一個隱式引用,因此不會對其進行垃圾收集,也不會從中釋放內存空間。這最多會導致不必要的高內存使用率,并導致應用程序崩潰,因為
class LeakingActivity: AppCompatActivity() {
private val listener = Listener()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_leaking)
}
override fun onStart() {
super.onStart()
GlobalSingleton.register(listener)
}
override fun onStop() {
super.onStop()
// we forget to unregister our listener so a reference
// of the Singleton to the listener and to the Activity
// still exists after the user navigates away fro that
// activity
// GlobalSingleton.unregister(listener)
}
// inner class has implicit reference to enclosing Activity
private inner class Listener : GlobalSingletonListener {
override fun onEvent() { }
}
}
object GlobalSingleton {
// a reference to the listener of the Activity is kept as long as
// unregister isn't called
private val listeners = mutableListOf()
fun register(listener: GlobalSingletonListener) {
listeners.add(listener)
}
fun unregister(listener: GlobalSingletonListener) {
listeners.remove(listener)
}
}
interface GlobalSingletonListener {
fun onEvent()
}
使用Android Studio 3.6查找內存泄漏
為了使用新的“泄漏檢測”功能檢查應用程序是否存在泄漏,您必須啟動Android Studio內存探查器。如果您是在Android 7.1或更低版本的設備上運行應用程序,則必須啟用高級分析才能查看所有分析數據。單擊導航欄中的“配置文件應用程序”,安裝、啟動并配置您的應用程序。
要開始分析已經運行的應用程序,只需單擊Android Studio底部欄中的“Profiler”,然后單擊(+)添加會話:
我切換到我的模擬器,打開和關閉泄漏活動兩次。在探查器中,我們看到LeakingActivity被創建,然后被銷毀。
現在我們想知道這個活動是否被垃圾收集。因此,我們必須通過單擊內存通道來打開內存探查器,這在我看來有點不直觀。我們可以看到為不同類別的對象(Java、Native、Graphics…)分配的所有內存。
接下來,我們必須通過單擊頂部的圖標來轉儲Java堆。
通過單擊force garbage collection first強制垃圾收集是有意義的,只是為了確保垃圾收集確實發生了。
轉儲完成后,我們可以看到所有內存分配:
Android Studio 3.6中的新功能。是以下復選框:
通過選中此新復選框,我們可以看到我們的LeakingActivity泄漏了兩次:
調查內存泄密的原因
下一步我們顯然要做的是修復漏洞。當對不再使用的“死”對象的引用仍然存在時,就會發生內存泄漏。我們需要找到這些參考資料并把它們處理掉。讓我們通過單擊LeakingActivity打開右側面板上的實例視圖來進行一些調查。
通過單擊實例前面的箭頭,我們可以在“引用視圖”中看到對該實例的所有引用:
老實說,我不知道找到導致泄漏的確切參考路徑的最佳方法是什么。我做了一些研究來找出LeakCanary是如何得到導致泄漏的參考路徑的。在LeakCanary中,此路徑稱為“Leak Trace”,根據其文檔,它是“從垃圾收集根到保留對象的最佳強引用路徑”。在其他地方,我看到它是最短路徑。垃圾收集根是永遠不會被垃圾收集的對象(比如應用程序對象,或者在我們的例子中是單例對象)。
保留的對象是LeakingActivity。我不確定是否可以在實例視圖中看到引用的類型(強、弱等)。但是,我們可以根據深度來排序引用,這是根據內存探查器文檔“從任何垃圾收集根到所選實例的最短躍點數”。
當我們查看最短深度為3的引用的第一條路徑時,我們可以確定以下引用鏈:GlobalSingleton(垃圾收集根)有一個對listener ArrayList的引用,它有一個對活動的listener內部類的引用,該類有一個對LeakingActivity的(隱式)引用。
這看起來很可疑,因為GlobalSingleton不應該引用已銷毀的活動,然后我們意識到忘記注銷偵聽器。
class LeakingActivity: AppCompatActivity() {
private val listener = Listener()
...
override fun onStop() {
super.onStop()
// fixing the leak by unregistering the listener
GlobalSingleton.unregister(listener)
}
...
}
我們發現并修復了新的泄漏通過Android Studio檢測功能!所以我們不再需要金絲雀了,對吧?
嗯,使用LeakCanary來檢測漏洞還是有很多好處的。
首先,LeakCanary總是監視你的應用程序是否存在漏洞。使用Android Studio Profiler,你必須主動監控你的應用程序,我們都知道,作為開發人員,我們通常有很多其他事情要做,而且傾向于“稍后”進行分析(也就是從不)。LeakCanary不斷地“提醒”你還有一些漏洞需要修復,這增加了你實際修復它們的機會。
第二,使用LeakCanary更容易找到泄漏的原因。我們不必深究android studio令人困惑的“參考視圖”,但可以得到一個很好的“泄漏跟蹤”。它甚至在最有可能導致泄漏的參考點下方畫了一條紅色的曲線。
第三,LeakCanary收集了庫和Android框架中已知的漏洞,因此它不會向您顯示無法修復的漏洞。此外,通過將LeakCanary添加到objectWatcher,您不僅可以檢測活動或片段的泄漏,還可以檢測任何其他對象(例如服務或Dagger組件)的泄漏。
此外,其他特性,如在生產中計數保留對象或在運行儀表測試時進行泄漏檢測,也非常有用。
結論
android studio3.6新的“泄漏檢測”功能是一種很好的、方便的方法,可以檢測泄漏的片段和活動,而無需向應用程序中添加第三方庫。在我看來,偶爾檢查一下小型或業余愛好的應用程序是否有漏洞就足夠了。不過,找出內存泄漏的原因并不是那么容易。對于任何關心低內存占用率和
總結
以上是生活随笔為你收集整理的android内存泄漏原因分析,Android Studio3.6的内存泄漏检测功能 VS LeakCanary的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言输出精确圆周率,如何设计C语言程序
- 下一篇: 高密中骏世界城商场属于哪个公司