You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何排查Android应用Native堆内存分配及疑似泄漏问题?

调试方案

步骤1:确认JIT缓存占用根因

你观察到的[anon:scudo:primary]高占用,结合Perfetto显示的分配来自/memfd:jit-cache (deleted)、触发源为String.matches,优先排查正则表达式使用问题:

  • 遍历代码中所有String.matches调用、Pattern实例创建逻辑,确认是否存在大量动态生成正则表达式、未复用Pattern实例的场景:Android 11的ART JIT会为频繁调用的正则匹配逻辑生成native代码缓存,若每次调用都创建新的Pattern实例,会导致JIT缓存无限膨胀,且这部分内存属于Scudo管理的Native堆,不会被普通GC回收
  • 临时验证方案:在应用的debuggable构建中执行命令关闭JIT,观察Native堆占用是否回归正常:
adb shell setprop debug.mono.extra jit:false
adb shell am force-stop <你的应用包名>
# 重启应用复现操作后再查dumpsys meminfo

步骤2:完整采集Scudo堆分配信息

Malloc Debug仅dump出30MB是因为默认配置未包含Scudo的元数据缓存、未释放的页块,调整配置采集全量分配栈:

  • 开启Malloc Debug的全栈采集,针对Scudo优化配置:
adb shell setprop wrap.<你的应用包名> 'LIBC_DEBUG_MALLOC_OPTIONS=backtrace=1,backtrace_max_stack_depth=32,fill_on_alloc=1 logwrapper'
adb shell am force-stop <你的应用包名>
  • 复现内存增长后,执行am dumpheap -n <PID> /data/local/tmp/native_heap.hprof,将导出的文件用Android Studio的Profiler或者相关解析工具读取,就能看到所有Scudo堆的分配调用栈。

步骤3:排除Scudo页保留特性的误判

Scudo分配器默认会保留释放的内存页不立即返回给系统,用来提升后续分配的性能,部分场景下会出现Heap Alloc很小但Private Dirty很高的情况:

  • 执行以下命令强制Scudo释放所有空闲页,执行后再查dumpsys meminfo的Native Heap值,如果占用大幅下降就属于正常的分配器缓存,不属于泄漏:
adb shell kill -10 <PID>

注:信号10是Scudo预留的强制回收空闲内存的信号,仅对Android 10及以上系统生效

步骤4:验证修复效果

如果确认是Pattern未复用导致的JIT缓存膨胀,修改代码后做对比测试:

  • 所有固定正则表达式提前编译为静态Pattern实例,重复使用
  • 动态正则的场景限制缓存数量,避免无限创建新Pattern
  • 再次复现操作流程,观察[anon:scudo:primary]的占用是否下降到同设备其他应用的平均水平(25%总PSS左右)

内容的提问来源于stack exchange,提问作者Irfan Latif

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 12:45:04