fd泄漏檢測

一.摘要

我們在分析fd泄漏問題的時候一般的通用方法是在/proc/pid/fd下不斷的ls -al | wc -l統計fd數量,並且查看哪個fd不斷的增多,然後再去代碼中排查對應的代碼,有時候光看fd並不容易找到泄漏的地方。本文章將介紹高通的leakdetect方法。

 

二.leakdetect使用介紹

默認情況下手機已經包含了fd泄漏的檢測代碼,具體路徑在:bionic/libc/malloc_debug/,它可以監控:file(1),socket(2),mmap(3)

具體原理就不多說了,有興趣的自己看源碼吧,下邊介紹使用方法:

1.adb root 

2.adb shell setprop libc.debug.leakdetect 1(1代表監控file,2代表監控socket,3代表監控mmap)

3.adb shell setprop libc.debug.leakdetect.program app_process(安卓進程填app_process,native進程填對應的進程名字)

4.adb shell stop 

5.adb shell start

6.adb shell kill -28 pid(你要監控的進程)

7.當你的fd不斷增加的時候再次輸入:adb shell kill -28 pid

你會在logcat中看到對應的結果:O機器關鍵字:fd_leak_debug Q機器關鍵字:malloc_debug

 

三.結果展示

file泄漏檢測結果:

06-02 11:59:34.040  5534 17218 E fd_leak_debug: Leak Type: file, count = 1, fd = 173, path = anon_inode:dmabuf

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #00  pc 0000000000004bd8  /system/lib64/libc_leak_detector.so (dup+124)

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #01  pc 00000000000070f0  /system/lib64/libcutils.so (native_handle_clone+144)

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #02  pc 0000000000005e84  /vendor/lib64/hw/[email protected] (android::hardware::graphics::mapper::V2_0::implementation::GrallocMapper::importBuffer(android::hardware::hidl_handle const&, std::__1::function<void (android::hardware::graphics::mapper::V2_0::Error, void*)>)+80)

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #03  pc 000000000001896c  /system/lib64/[email protected]

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #04  pc 0000000000014600  /system/lib64/libui.so (android::Gralloc2::Mapper::importBuffer(android::hardware::hidl_handle const&, native_handle const**) const+88)

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #05  pc 0000000000017dc4  /system/lib64/libui.so (android::GraphicBufferMapper::importBuffer(native_handle const*, native_handle const**)+108)

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #06  pc 0000000000016a04  /system/lib64/libui.so (android::GraphicBuffer::unflatten(void const*&, unsigned long&, int const*&, unsigned long&)+604)

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #07  pc 00000000001373c8  /system/lib64/libandroid_runtime.so

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #08  pc 000000000006b9a4  /system/lib64/libbinder.so (android::Parcel::read(android::Parcel::FlattenableHelperInterface&) const+464)

06-02 11:59:34.040  5534 17218 E fd_leak_debug:           #09  pc 0000000000136e1c  /system/lib64/libandroid_runtime.so

mmap泄漏檢測結果:

06-01 20:47:01.342 17087 19660 E malloc_debug: Leak Type: mmap, count = 1, addr = 0x794fee8000

06-01 20:47:01.342 17087 19660 E malloc_debug:           #00  pc 000000000000084c  /system/lib64/libc_leak_detector.so (mmap+180)

06-01 20:47:01.342 17087 19660 E malloc_debug:           #01  pc 0000000000007bcc  /apex/com.android.runtime/lib64/libartbase.so (art::MemMap::MapInternal(void*, unsigned long, int, int, int, long, bool)+88)

06-01 20:47:01.342 17087 19660 E malloc_debug:           #02  pc 0000000000007844  /apex/com.android.runtime/lib64/libartbase.so (art::MemMap::MapAnonymous(char const*, unsigned char*, unsigned long, int, bool, bool, art::MemMap*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*, bool)+280)

06-01 20:47:01.342 17087 19660 E malloc_debug:           #03  pc 000000000017aa84  /apex/com.android.runtime/lib64/libart.so (art::IndirectReferenceTable::IndirectReferenceTable(unsigned long, art::IndirectRefKind, art::IndirectReferenceTable::ResizableCapacity, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+176)

06-01 20:47:01.342 17087 19660 E malloc_debug:           #04  pc 0000000000258890  /apex/com.android.runtime/lib64/libart.so (art::JNIEnvExt::JNIEnvExt(art::Thread*, art::JavaVMExt*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+52)

06-01 20:47:01.342 17087 19660 E malloc_debug:           #05  pc 00000000002587fc  /apex/com.android.runtime/lib64/libart.so (art::JNIEnvExt::Create(art::Thread*, art::JavaVMExt*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>*)+52)

06-01 20:47:01.342 17087 19660 E malloc_debug:           #06  pc 00000000003ce91c  /apex/com.android.runtime/lib64/libart.so (art::Thread::CreateNativeThread(_JNIEnv*, _jobject*, unsigned long, bool)+400)

06-01 20:47:01.342 17087 19660 E malloc_debug:           #07  pc 0000000000308f28  /apex/com.android.runtime/lib64/libart.so

06-01 20:47:01.342 17087 19660 E malloc_debug:           #08  pc 0000000000007fec  /system/framework/arm64/boot.oat

06-01 20:47:01.342 17087 19660 E malloc_debug:           #09  pc 00000000003dcbf5  /apex/com.android.runtime/javalib/core-oj.jar

四.hprof輔助分析

    我們有了調用棧後還可以看下是哪個對象持有了這個fd,那麼我們就需要抓一個hprof輔助分析,抓取方法:adb shell am dumpheap com.android.settings /data/local/tmp/settings.hprof,然後將settings.hprof pull到電腦上並打開,我們這裏以“file泄漏檢測結果”中的“file泄漏檢測結果“來舉例,之前我們已經看到了是和GraphicBuffer相關,那麼我們在hprof中找到GraphicBuffer,我們發現它的引用關係是:ActivityManager->TaskSnapshot->mSnapshot

繼續搜索:TaskSnapshot

我們發現這裏創建了很多TaskSnapshot,因爲TaskSnapshot中又包含了一個GraphicBuffer,所以這個時候我們就去排查TaskSnapshot爲什麼被一直被創建並且沒有被回收

五.總結

    有了調用棧之後我們再去分析那就簡單了很多了,不需要翻遍源碼到處找在哪裏泄漏了,直接從調用棧出發查問題就好了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章