Native内存基础
Native内存的基本概念
- 物理内存(PSS)硬件概念
- RAM硬件
- 虚拟内存(VSS)操作系统概念,为了解决物理内存不足的问题
- 内存分页
- 缺页中断
- 页面置换
- 安卓应用内存使用(均在用户空间内
user space:相对于kernel space的概念)- Java使用内存
- Java heap size * 2
- Android oat/art文件
- Native可用内存
- 除Java之外的用户空间
- Java使用内存
- App & Device运行时 用户空间虚拟内存上限(Native OOM的本质:用户空间虚拟内存耗尽)
- 32位App & 32位Device:最大3G左右
- 32位App & 64位Device:最大4G左右
- 64位App & 64位Device:最大512G左右(是不是超大?所以64位app几乎不会有native OOM问题,支持64位app也是治理OOM途径之一)

Native内存的分配方式
无论是*alloc还是mmap都不能直接分配物理内存,只能分配虚拟内存,但是*alloc系函数分配小块内存可能直接映射到物理内存。Thread、Webview、Flutter、显存内存分配基本都是走mmap虚拟内存
PSS
- 不能直接被分配 只能被映射
- malloc/calloc/realloc/memalign
- free
- posix_memalign
- aligned_alloc
- malloc_usable_size
- pvalloc/valloc
VSS
- 当*alloc函数分配内存 >=128k 时,底层调用mmap
- mmap/mmap64
- munmap
- mremap
Native内存不足的表现
- Java Crash(pthread_create OOM)
- Native Crash
- 黑屏(底层做了异常处理,可能以黑屏方式体现)
栈回溯
- 由调用栈栈顶向栈底推到调用链的过程
- 通常用在打印crash堆栈(例如Java层的
printStackTrace())
Native内存泄漏工具
目的:找出用户虚拟内存空间被哪些业务逻辑耗尽(不光聚焦虚拟内存,还需聚焦物理内存,提高虚拟内存使用率,即找出虚拟内存中申请但未在物理内存中分配的内存,另外随着64位app的普及,在虚拟内存耗尽之前,物理内存会先耗尽并产生ANR/重启等后果)
Native内存泄漏原理
Why:与Java层不同,Java层相当于在Native层上又做了一次抽象,可以比较容易理清内存块的属性和依赖关系,所以Native内存不能像Java那样进行静态分析,只能渗透到内存分配的过程监控内存分配/释放过程
How:类似于筛子模型,过滤出分配了但没释放的内存
- Native内存泄漏监控原理
- 通过代理拦截内存分配的地址和大小
- 通过回溯调用栈获取内存分配的调用链(相比Java是通过依赖关系获取引用链,然后通过引用链获得调用链)
- 通过缓存crud过滤出未释放的内存
- Native内存泄漏监控组成
- 代理
- 栈回溯
- 缓存管理

已有工具/解决方案
- Malloc Debug:AOSP原生支持,难堪大用
- 稳定性问题:存在栈回溯crash
- 性能问题:性能损失十倍以上
- LeakTracer:依赖LD_PRELOAD机制和系统栈回溯实现
- MTrace:仅支持malloc/realloc等 不支持new/new[]等
- MemWatch
- Valgrind-memcheck
- TCMalloc
- LeakSanitizer
- 高德系统化解决方案
代理方案/栈回溯方案/缓存管理方案对比
代理方案
- Malloc hook:Android7以上,debug包,wrap.sh
- LD_PRELOAD:依赖Android版本 debug包 wrap.sh
- PLT/GOT hook:xHook
- Inline hook:Android inline hook
| 模式 | hook原理 | 优点 | 缺点 |
|---|---|---|---|
| Malloc hook | AOSP原生代理实现 | 没有性能/稳定性问题 | 接口不暴露,不支持mmap |
| LD_PRELOAD | so加载先后顺序 | 没有性能/稳定性问题 | Android上难以实现 |
| PLT/GOT hook | 跳转表 | 单点hook 成熟可靠 | hook效率低 |
| Inline hook | 目标代码 | 全局hook 效率高 | 兼容性问题多 风险大 |
栈回溯方案
- libunwind_llvm:LLVM内置unwind库,libunwind llvm编年史
- libunwind_nongnu:第三方unwind实现
- libgcc_s:GCC内置unwind库
- libbacktrace:AOSP内置
- libunwindstack:Android9.0新方案
- libudf:MTK实现
| Unwind | 性能 | 兼容性 | 支持 |
|---|---|---|---|
| libudf | 性能最好 | 兼容性好 | 无更新 |
| libunwind_llvm | 性能较好 | 兼容性差 | 会被取代 |
| libunwind_nongnu | 性能最差 | 兼容性好 | 官方持续更新 |
缓存管理方案
- Malloc Debug:全局锁,hash散列,栈聚合,动态申请缓存空间
- LeakTracer:全局锁,大缓存,hash散列,缓存满之后动态申请缓存空间