记一次Android进程native内存泄漏分析

1.环境

Android16,设备是userdebug

2.使用下面命令检查是否有内存泄漏

adb shell dumpsys meminfo --unreachable 26718,其中26718是应用的进程号,输出如下,Unreachable memory是native未回收的内存

Applications Memory Usage (in Kilobytes):

Uptime: 5082822 Realtime: 5082822

** MEMINFO in pid 10085 com.crab.test.kotlin.mediandktest **

Pss Private Private Swap Rss Heap Heap Heap

Total Dirty Clean Dirty Total Size Alloc Free


Native Heap 12700 12700 0 0 12700 17772 11340 2492

Dalvik Heap 9712 9712 0 0 9712 18880 9440 9440

Dalvik Other 2968 2820 0 0 3116

Stack 680 680 0 0 680

Ashmem 625 0 0 0 1892

Other dev 25 0 24 0 1104

.so mmap 19525 7316 3012 0 100316

.jar mmap 6018 0 368 0 66176

.apk mmap 12186 28 10564 0 16260

.ttf mmap 312 0 132 0 1264

.dex mmap 197 8 0 0 1580

.oat mmap 233 0 0 0 10708

.art mmap 32913 32872 8 0 33188

Other mmap 50662 2432 46804 0 55932

Unknown 2916 2852 64 0 2916

TOTAL 151672 71420 60976 0 317544 36652 20780 11932

App Summary

Pss(KB) Rss(KB)


Java Heap: 42592 42900

Native Heap: 12700 12700

Code: 21452 196624

Stack: 680 680

Graphics: 0 0

Private Other: 54972

System: 19276

Unknown: 64640

TOTAL PSS: 151672 TOTAL RSS: 317544 TOTAL SWAP (KB): 0

Objects

Views: 17 ViewRootImpl: 1

AppContexts: 5 Activities: 1

Assets: 3 AssetManagers: 0

Local Binders: 15 Proxy Binders: 65

Parcel memory: 6 Parcel count: 25

Death Recipients: 0 WebViews: 0

Native Allocations

Count Total(kB)


Other (malloced): 511 47

Other (nonmalloced): 83 62

Bitmap (malloced): 4 970

SQL

MEMORY_USED: 0

PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0

Unreachable memory

1797 bytes in 36 unreachable allocations

ABI: 'arm64'

56 bytes unreachable at 796666c290

referencing 1677 unreachable bytes in 34 allocations

first 32 bytes of contents:

796666c290: d0 22 64 26 7b 00 00 b4 38 a1 60 96 7a 00 00 b4 ."d&{...8.`.z...

796666c2a0: 08 97 9b e1 7b 00 00 00 00 00 00 00 00 00 00 00 ....{...........

64 bytes unreachable at 7966612b50

first 20 bytes of contents:

7966612b50: 55 73 65 72 2d 41 67 65 6e 74 3a 20 73 74 61 67 User-Agent: stag

7966612b60: 65 66 72 69 67 68 74 2f 31 2e 32 20 28 4c 69 6e efright/1.2 (Lin

3.开启Malloc Debug(应用级别)

根据文档路径(源码根目录/bionic/libc/memory/malloc_debug/README.md),"For app developers" 章节,使用 wrap.<包名> 属性开启:

如果 Android 12+ 且遇到问题,先执行这个修复命令(可选)

adb shell setprop dalvik.vm.force-java-zygote-fork-loop true

开启 malloc debug,记录 backtrace

adb shell setprop wrap.com.crab.test.kotlin.mediandktest '"LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper"'

com.crab.test.kotlin.mediandktest是应用的包名

验证属性是否设置成功:

adb shell getprop | grep wrap

应该看到: wrap.com.crab.test.kotlin.mediandktest: LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper

4.重复执行第二步可以看到下面输出

Applications Memory Usage (in Kilobytes):

Uptime: 11497639 Realtime: 11497639

** MEMINFO in pid 26718 com.crab.test.kotlin.mediandktest **

Pss Private Private Swap Rss Heap Heap Heap

Total Dirty Clean Dirty Total Size Alloc Free


Native Heap 20016 20016 0 0 20016 25056 18276 2852

Dalvik Heap 9572 9572 0 0 9572 18864 9432 9432

Dalvik Other 2988 2844 0 0 3132

Stack 884 884 0 0 884

Ashmem 625 0 0 0 1892

Other dev 656 0 24 0 2764

.so mmap 27268 7436 9656 0 111332

.jar mmap 6362 0 684 0 66596

.apk mmap 12231 28 10592 0 16324

.ttf mmap 312 0 132 0 1264

.dex mmap 205 8 16 0 1580

.oat mmap 272 0 16 0 10604

.art mmap 32913 32872 8 0 33188

Other mmap 50728 2496 46800 0 56068

Unknown 2932 2868 64 0 2932

TOTAL 167964 79024 67992 0 338148 43920 27708 12284

App Summary

Pss(KB) Rss(KB)


Java Heap: 42452 42760

Native Heap: 20016 20016

Code: 28596 208016

Stack: 884 884

Graphics: 0 0

Private Other: 55068

System: 20948

Unknown: 66472

TOTAL PSS: 167964 TOTAL RSS: 338148 TOTAL SWAP (KB): 0

Objects

Views: 17 ViewRootImpl: 1

AppContexts: 5 Activities: 1

Assets: 3 AssetManagers: 0

Local Binders: 15 Proxy Binders: 65

Parcel memory: 6 Parcel count: 25

Death Recipients: 0 WebViews: 0

Native Allocations

Count Total(kB)


Other (malloced): 511 47

Other (nonmalloced): 83 62

Bitmap (malloced): 4 970

SQL

MEMORY_USED: 0

PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0

Unreachable memory

1771 bytes in 33 unreachable allocations

ABI: 'arm64'

56 bytes unreachable at 752815af80

referencing 1651 unreachable bytes in 31 allocations

first 32 bytes of contents:

752815af80: f0 b4 0b 78 75 00 00 b4 18 62 00 a8 75 00 00 b4 ...xu....b..u...

752815af90: 08 37 56 9a 77 00 00 00 00 00 00 00 00 00 00 00 .7V.w...........

#00 pc 00000000000596ec /apex/com.android.runtime/lib64/bionic/libc.so (malloc+80)

#01 pc 000000000010289c /system/lib64/libc++.so (operator new(unsigned long)+28)

#02 pc 000000000007a158 /system/lib64/libmedia.so

#03 pc 000000000002036c /system/lib64/libmediandk.so

#04 pc 000000000001c724 /system/lib64/libstagefright_foundation.so (android::AHandler::deliverMessage(android::sp<android::AMessage> const&)+184)

#05 pc 000000000002373c /system/lib64/libstagefright_foundation.so (android::AMessage::deliver()+172)

#06 pc 000000000001dc24 /system/lib64/libstagefright_foundation.so (android::ALooper::loop()+536)

#07 pc 0000000000017e54 /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+536)

#08 pc 0000000000137b68 /system/lib64/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+144)

#09 pc 0000000000019eec /system/lib64/libutils.so

#10 pc 0000000000086580 /apex/com.android.runtime/lib64/bionic/libc.so

#11 pc 0000000000078d64 /apex/com.android.runtime/lib64/bionic/libc.so

64 bytes unreachable at 752801f580

first 20 bytes of contents:

752801f580: 55 73 65 72 2d 41 67 65 6e 74 3a 20 73 74 61 67 User-Agent: stag

752801f590: 65 66 72 69 67 68 74 2f 31 2e 32 20 28 4c 69 6e efright/1.2 (Lin

#00 pc 00000000000599bc /apex/com.android.runtime/lib64/bionic/libc.so (realloc+160)

#01 pc 0000000000028ca4 /system/lib64/libstagefright_foundation.so (android::AString::append(char const*, unsigned long)+120)

#02 pc 000000000002a2a0 /system/lib64/libstagefright_foundation.so

#03 pc 000000000007ca58 /system/lib64/libmediaplayerservice.so

#04 pc 0000000000059414 /apex/com.android.runtime/bin/linker64

#05 pc 00000000000593c0 /apex/com.android.runtime/bin/linker64

#06 pc 00000000000585fc /apex/com.android.runtime/bin/linker64

#07 pc 0000000000057fc4 /apex/com.android.runtime/bin/linker64

#08 pc 0000000000004024 /apex/com.android.runtime/lib64/bionic/libdl.so (dlopen+16)

#09 pc 00000000000fc890 /system/lib64/libaudioclient.so

#10 pc 000000000005946c /system/lib64/libaudioclient.so

#11 pc 0000000000059414 /apex/com.android.runtime/bin/linker64

#12 pc 00000000000593c0 /apex/com.android.runtime/bin/linker64

#13 pc 00000000000593c0 /apex/com.android.runtime/bin/linker64

#14 pc 00000000000593c0 /apex/com.android.runtime/bin/linker64

#15 pc 00000000000593c0 /apex/com.android.runtime/bin/linker64

5.从源码编译的out目录找到这些so库的符号链接,去找到对应的文件行号

比如Android16源码:

android/prebuilts/clang/host/linux-x86/clang-r574158/bin$ ./llvm-addr2line -f -C -e libstagefright_foundation.so 000000000001dc24

android::ALooper::loop()

frameworks/av/media/module/foundation/ALooper.cpp:280

android/prebuilts/clang/host/linux-x86/clang-r574158/bin$ ./llvm-addr2line -f -C -e libstagefright_foundation.so 000000000002373c

android::AMessage::deliver()

frameworks/av/media/module/foundation/AMessage.cpp:419

android/prebuilts/clang/host/linux-x86/clang-r574158/bin$ ./llvm-addr2line -f -C -e libstagefright_foundation.so 000000000001c724

android::AHandler::deliverMessage(android::sp<android::AMessage> const&)

frameworks/av/media/module/foundation/AHandler.cpp:28

android/prebuilts/clang/host/linux-x86/clang-r574158/bin$ ./llvm-addr2line -f -C -e lib

libmediandk.so libmedia.so libstagefright_foundation.so

android/prebuilts/clang/host/linux-x86/clang-r574158/bin$ ./llvm-addr2line -f -C -e lib

libmediandk.so libmedia.so libstagefright_foundation.so

android/prebuilts/clang/host/linux-x86/clang-r574158/bin$ ./llvm-addr2line -f -C -e libmediandk.so 000000000002036c

CodecHandler::onMessageReceived(android::sp<android::AMessage> const&)

frameworks/av/media/ndk/NdkMediaCodec.cpp:258

可以看到NdkMediaCodec.cpp:258泄漏了,我的代码如下:

case MediaCodec::CB_OUTPUT_FORMAT_CHANGED:

{

sp<AMessage> format;

if (!msg->findMessage("format", &format)) {

ALOGD("CB_OUTPUT_FORMAT_CHANGED: format is expected.");

break;

}

AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&format);

Mutex::Autolock _l(mCodec->mAsyncCallbackLock);

if (mCodec->mAsyncCallback.onAsyncFormatChanged != NULL) {

mCodec->mAsyncCallback.onAsyncFormatChanged(

mCodec,

mCodec->mAsyncCallbackUserData,

aMediaFormat);

}

break;

}

这里new了一个指针,异步回调给了应用层,应用层拿到这个指针没有释放,由于系统层也没有释放,所以就导致了内存泄漏。修改方法也很简单,应用层拿到这个指针的时候,在不需要使用时主动调用一次AMediaFormat_delete来释放指针就可以了。

相关推荐
weiggle11 小时前
第七篇:状态提升与单向数据流——架构设计的核心
android
xingpanvip11 小时前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
goldenrolan11 小时前
A公司物料替代测试系统 v1.7:从需求到 exe/apk 的 AI 辅助全链路实践
android·自动化测试·软件测试·python·ai
AC赳赳老秦13 小时前
用 OpenClaw 搭建服务器故障应急响应系统,自动处理 80% 常见运维故障
android·运维·服务器·python·rxjava·deepseek·openclaw
骇客之技术14 小时前
AutoLua:在安卓上写 Lua 脚本
android·junit·lua
kiros_wang15 小时前
Android 常见面试题
android
货拉拉技术15 小时前
Hook植入日志协助定位问题方案
android
FlightYe15 小时前
Android投屏MirrorCast全链路
android
Ehtan_Zheng15 小时前
Kotlin const val vs val:字节码、性能与隐藏陷阱详解
android·kotlin
墨狂之逸才16 小时前
Android TV 垃圾应用清理指南
android