当前位置: 首页 > news >正文

记一次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来释放指针就可以了。


http://www.jsqmd.com/news/888473/

相关文章:

  • 2025-2026年上海搬家公司推荐:五大口碑评测办公室搬迁高效停工注意事项性价比高 - 品牌推荐
  • FreeRTOS 实战:互斥量与优先级继承——从代码到现象完全解析
  • AI智能体构建:从概念到工程实践的完整指南
  • 告别多模型集成噩梦:DMXAPI如何用“改两行配置”统一调用DeepSeek、豆包等大模型
  • 冷门实用插件盘点,大幅缩减作图时长
  • AI重塑IT文档工作流:从日志到专业报告与SOP的自动化实践
  • Python数据类型转换实战:隐式陷阱、显式代价与结构迁移
  • 2025-2026年北京家庭定制游旅行社推荐:TOP5口碑产品评测三代同行避拥挤性价比高注意事项 - 品牌推荐
  • 版图新手避坑指南:画电阻时,为什么你的LVS总报错?(附蛇形连线实战)
  • AMD Ryzen 7 3800X + VMware 15.1.0 保姆级教程:手把手带你搞定macOS Catalina虚拟机(含避坑指南)
  • 2026年4月2205双相钢圆棒厂商推荐,2205不锈钢圆棒/904L不锈钢圆棒,2205双相钢圆棒品牌哪家好 - 品牌推荐师
  • awk入门
  • 昇腾CANN社区治理:一个PR从提交到合并的全过程
  • 2026年4月套膜机产品推荐,打包缠膜一体机/行李包装机/自动缠膜机/摇臂缠膜机/自动缠绕机/包装机,套膜机制造商如何选 - 品牌推荐师
  • 利用AI编程助手30分钟快速上手陌生代码库的方法论
  • Unity游戏翻译深度解析:XUnity.AutoTranslator原理与优化实战
  • Unity微信小游戏实战:突破首包限制与WXSS兼容性难题
  • 线程任务执行报错后,线程会不会挂掉,Java线程池
  • 多平台同稿如何一键改写?5款AI文案工具对比帮你避坑
  • Python TDD实战入门:从red-green-refactor到高覆盖率测试套件
  • Git 给 main 分支打 Tag(版本标记)完整教程
  • 昇腾CANN开源竞赛,从参赛到获奖的实战攻略
  • UOS系统维护实战:用一条命令批量清理旧内核与无用依赖,为你的系统‘瘦身’
  • 2026年5月上海搬家公司推荐:五个口碑搬家服务专业评测价格适用场景 - 品牌推荐
  • AI智能体规模化运维:从上下文污染到系统防劣化的工程实践
  • WebStorm提交Gitee失败:31mlncorrect错误与access token认证详解
  • ops-transformer的MoE算子,让混合专家模型训练快5倍
  • 源代码论文分享|基于Java的企业OA管理系统的设计与实现!
  • 保姆级教程:在Windows上从零跑通TASSEL 5.0的GWAS分析(附示例数据避坑指南)
  • linux配置DNS主从服务器的实验步骤