close

最近在調試Android Native層的內存泄漏問題,整理了一些筆記,分享一下


本文目錄

如何查看內存信息?
Android 關鍵內存項介紹
如何調試內存泄漏
其他工具
復盤
相關資料推薦
如何查看內存信息?

在代碼中打印,開啟一個線程,間隔固定時間打印出當前內存信息【有好多種獲取內存信息的API,這裡只列出其中一種方式,親測有效】

private void startMemProfiler() { new Thread(new Runnable() { @Override public void run() { while (true) { displayMemory(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();}private void displayMemory() { final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo(); activityManager.getMemoryInfo(info); Log.i(TAG, "系統剩餘內存:" + (info.availMem / (1024 * 1024)) + "M"); Log.i(TAG, "系統是否處於低內存運行:" + info.lowMemory); Log.i(TAG, "當系統剩餘內存低於" + (info.threshold / (1024 * 1024)) + "M" + "時就看成低內存運行"); Log.i(TAG, "系統已經分配的native內存:" + (Debug.getNativeHeapAllocatedSize() / (1024 * 1024)) + "M"); Log.i(TAG, "系統還剩餘的native內存:" + (Debug.getNativeHeapFreeSize() / (1024 * 1024)) + "M"); Log.i(TAG, "系統的所有native內存大小:" + (Debug.getNativeHeapSize() / (1024 * 1024)) + "M");}

使用adb命令行

adb shell dumpsys meminfo /adb shell dumpsys meminfo tv.danmaku.bili

dumpsys meminfo顯示的信息如圖所示:

Android 關鍵內存項介紹


這裡僅介紹我們需要重點關注的字段:

Dalvik Heap:虛擬機占用的內存,可以理解為Java層占用的內存。

Native Heap:Native層占用的堆內存,可以理解為C/C++側占用的內存。【我們需要重點關注的項】

Private Dirty/Clean:進程私有的內存,進程銷毀後,該部分內存可以被回收【Dirty/Clean:該頁面是否被修改過,如果被修改過,即dirty,在頁面被淘汰的時候,就會把該頁面換出。】

VSS(Virtual Set Size):表示一個進程可訪問的全部內存地址空間的大小。這個大小包括了進程已經申請但尚未使用的內存空間。在實際中很少用這種方式來表示進程占用內存的情況,用它來表示單個進程的內存使用情況是不準確的。【圖中沒有展示,但Linux中有這個東西】

RSS(Resident Set Size):表示一個進程在RAM中實際使用的空間地址大小,包括了全部共享庫占用的內存,這種表示進程占用內存的情況也是不準確的。【圖中沒有展示,但Linux中有這個東西】

PSS(Proportional Set Size):表示一個進程在RAM中實際使用的空間地址大小,它按比例包含了共享庫占用的內存。假如有3個進程使用同一個共享庫,那麼每個進程的PSS就包括了1/3大小的共享庫內存。這種方式表示進程的內存使用情況較準確,但當只有一個進程使用共享庫時,其情況和RSS一模一樣。【PSS 衡量的一個優點是,可以將所有進程的 PSS 加起來確定所有進程占用的實際內存。這表示 PSS 是一種理想的方式,可用來衡量進程的實際 RAM 占用比重,以及相對於其他進程和可用的總 RAM 而言,對 RAM 的占用情況。】

USS(Unique Set Size):表示一個進程本身占用的內存空間大小,不包含其它任何成分,這是表示進程內存大小的最好方式!【圖中沒有展示,但Linux中有這個東西】【所以有:VSS>=RSS>=PSS>=USS】

Graphics:圖形緩衝區隊列為向屏幕顯示像素(包括 GL 表面、GL 紋理等等)所使用的內存。(請注意,這是與 CPU 共享的內存,不是 GPU 專用內存。)【官方文檔這麼說的,具體啥意思我也沒看懂,https://developer.android.com/studio/profile/memory-profiler】

其他字段如果想要了解可以參考官方文檔:https://developer.android.com/studio/command-line/dumpsys

如何調試內存泄漏


通過排除法 + 打印當前內存信息(上面介紹過)的方法,懷疑哪裡就注釋掉哪裡,看還會不會有泄漏【比較糙】。

代碼層全局覆蓋malloc和free,本質就是記錄下來每個malloc的節點,存到鍊表里,free的時候將節點從鍊表里移除,如果最後鍊表中還有節點,則表示有內存泄漏。【大多數場景中好用,但只能檢測當前代碼內存的C語言代碼,不能檢測其他庫的泄漏】

重載operator new 和 operator delete,原理和上面類似。【只能檢測C++使用new delete操作的內存,不能檢測malloc和free操作的內存】

使用Android Studio Profiler工具:需要Android10以上版本,具體可以看:https://developer.android.com/studio/profile/memory-profiler。【整體感覺不太好用】

在Demo側集成tencent/matrix,可以選擇hook某個動態鏈接庫下的malloc和free符號,如果發現某個動態庫中存在內存泄漏,會打印出泄漏的堆棧信息。【推薦使用】

matrix的使用

通過集成matrix庫,可以選擇hook某個動態鏈接庫的malloc和free符號,然後工作方式和libctools類似,存儲malloc的節點,free時候就刪除該節點,最後統計內存泄漏情況。

matrix的集成方式可以看github庫:https://github.com/Tencent/matrix

hook的原理可以看:https://github.com/iqiyi/xHook/blob/master/docs/overview/android_plt_hook_overview.zh-CN.md

如果出現內存泄漏,會有json和log後綴的文件,如圖:

json文件會統計哪個庫泄漏了多少內存,log文件會記錄具體泄漏的堆棧信息。

拿到具體泄漏的堆棧信息後,可以通過addr2line工具定位到具體的代碼:

/Users/xxx/Android/ndk/21.4.7075529/toolchains/llvm/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line -C -f -e /Users/xxx/project/java/build/intermediates/stripped_native_libs/debug/out/lib/arm64-v8a/libBMMCapture-Android.so 83a70

效果如圖:

其它工具


dumpsys還有一些其它功能,使用方式如下:

內存 adb shell dumpsys meminfo

CPU adb shell dumpsys cpuinfo

幀率 adb shell dumpsys gfxinfo

顯示 adb shell dumpsys display

電源 adb shell dumpsys power

電池狀態 adb shell dumpsys batterystats

電池 adb shell dumpsys battery

鬧鐘 adb shell dumpsys alarm

位置 adb shell dumpsys location

復盤拍攝內存泄漏排查


背景:每次出現內存泄漏時,經常懷疑是某個模塊或者其他庫更新導致,但又沒有證據,沒有合適的排查內存泄漏的方法論。

分析與解決:

■接入每個三方庫時,都寫一個Demo,進行效果測試、內存測試、性能測試,每次更新三方庫時,都跑一下Demo。或者每次出問題時,跑一下Demo看是不是這個庫導致的問題。

■集成第三方庫時,降低代碼耦合性,保證可以靈活去掉某個三方庫,可考慮使用條件編譯等手段,方便排查問題。

■引入工具排查:

○內存泄漏:Android使用matrix,iOS使用Xcode

○cpu占用率:Android profiler, iOS Xcode

○gpu占用率:Android 高通使用snapdragonprofiler,或者perfdog(收費)

相關資料推薦

https://developer.android.com/topic/performance/memory-management?hl=zh-cn

https://developer.android.com/studio/profile/memory-profiler

https://developer.android.com/studio/command-line/dumpsys

https://github.com/iqiyi/xHook/blob/master/docs/overview/android_plt_hook_overview.zh-CN.md

參考資料

https://developer.android.com/studio/command-line/dumpsys

https://blog.csdn.net/pugongying1988/article/details/16838859

https://www.jianshu.com/p/8203457a11cc

點個在看你最好看

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()