在系统运行过程中,使用android自带的procrank工具,查看系统内存情况,例如
130|shell@android:# procrank | head
warning: could not create process interface for 8695
PID Vss Rss Pss Uss Swap PSwap cmdline
2524 353316K 145292K 141318K 139760K 0K 0K /system/bin/mediaserver
3866 1030380K 58352K 34293K 33188K 1096K 26K com.autonavi.amapautolite
797 1102276K 53088K 27254K 25688K 1080K 29K system_server
1247 981064K 41256K 18633K 17824K 1132K 27K com.iflytek.inputmethod
1099 1006660K 42044K 17814K 16576K 1116K 54K com.android.systemui
明显可以看出mediaserver进程的内存偏高,存在内存泄漏的情况,亦或者可能是频繁的内存分配/释放导致的内存碎片问题,不过大部分情况都是内存泄漏。
针对mediaserver的内存泄漏,Android已经提供了非常好的工具来分析。想必是开发过程中google也遇到这个进程不少的内存泄漏情况,也导致新版本的Android已经将这个进程拆分成多个子进程,好收敛问题。
言归正传。
Android针对内存泄漏的情况,有一个libc_malloc_debug.leak.so来替代libc,这个库可以通过编译bionic来得到。它会记录每次内存分配/释放的堆栈,这样我们周期性的打印这些堆栈,通过前后的对比,就可以看到内存的变化情况。
首先,要让link启动进程的时候加载这个库,而非libc.so,需要做以下设置:
setprop libc.debug.malloc 1
setprop libc.debug.malloc.program mediaserver
意思是只debug mediaserver的内存情况,而且只针对内存泄漏,其他设置内容可以参考代码。
开机以后,可以运行
dumpsys media.player -m
系统会调用
MediaPlayerService::dump =>
dumpMemoryAddresses(fd) =>
get_malloc_leak_info (libc_malloc_debug.leak.so)
可以打印如下的堆栈,其中记录了内存占用总量,以及每一块内存的分配堆栈
等系统运行一段时间以后,再次dumpsys,就可以得到下图的比较,其中右侧红色的部分就有可能是内存泄漏的项目
以上已经大致看到了可能的内存泄漏情况,那么如何查找到对应的代码呢?
此时我们可以打印进程的maps文件,来得到系统库的内存分布,命令如下:
如果我们得到一段泄漏的堆栈情况:
size 64, dup 62340, 0xb314b50e, 0xb6ed8376, 0xb69a3b1c, 0xb32ba0e4, 0xb32ba586, 0xb32a81f4, 0xb451b03e, 0xb451d1b4, 0xb688972a, 0xb688a56e, 0xb688953e, 0xb6899c74, 0xb6899dc2, 0xb6899e6c, 0xb699acc0, 0xb6edc642, 0xb6eda5f6
有点天书的样子,不过有进程的maps,又有这里的堆栈,实际上每个地址都可以在maps当中查到对应的库,然后减去库的首地址,就可以得到库当中的偏移地址,使用addr2line就可以得到实际对应的代码了。
使用以下脚本
参考脚本
可以得到如:
MAPFILE=maps.txt STACKFILE=stack.txt ROOTPATH=~/out/target/product/joyasz6580_weg_l/symbols
callstack = size 3133464, dup 12, 0xb30c650e, 0xb30c6914, 0xb6e5339e, 0xaee22478, 0xaee1c770, 0xb5e7bdda, 0xb69cb1ce, 0xb69cb370, 0xb69d3e04, 0xb6322334, 0xb69cc792, 0xb69d359c, 0xb632219c, 0xb69c523a, 0xb6322f4e, 0xb63228a4, 0xb6915cc0, 0xb691582e, 0xb6e57642, 0xb6e555f6
Ignore not address: size
Ignore not address: 3133464
Ignore not address: dup
Ignore not address: 12
findAddrInMap: targetAddr 0xb30c650e
path=~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libc_malloc_debug_leak.so offsetHex=650e
leak_malloc
~/bionic/libc/bionic/malloc_debug_leak.cpp:315 (discriminator 1)
findAddrInMap: targetAddr 0xb30c6914
path=~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libc_malloc_debug_leak.so offsetHex=6914
leak_memalign
~/bionic/libc/bionic/malloc_debug_leak.cpp:473
findAddrInMap: targetAddr 0xb6e5339e
path=~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libc.so offsetHex=1239e
memalign
~/bionic/libc/bionic/malloc_debug_common.cpp:276
findAddrInMap: targetAddr 0xaee22478
path=~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libMtkOmxVenc.so offsetHex=11478
addr2line: '~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libMtkOmxVenc.so': No such file
findAddrInMap: targetAddr 0xaee1c770
path=~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libMtkOmxVenc.so offsetHex=b770
addr2line: '~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libMtkOmxVenc.so': No such file
findAddrInMap: targetAddr 0xb5e7bdda
path=~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libstagefright_omx.so offsetHex=15dda
android::OMXNodeInstance::allocateBuffer(unsigned int, unsigned int, unsigned int*, void**)
~/frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp:880
findAddrInMap: targetAddr 0xb69cb1ce
path=~/out/target/product/joyasz6580_weg_l/symbols/system/lib/libstagefright.so offsetHex=a91ce
android::ACodec::allocateBuffersOnPort(unsigned int)
~/frameworks/av/media/libstagefright/ACodec.cpp:1158
以上就得到了需要确认的代码内存,白盒查一下是否真的有内存泄漏吧。