Android 内存全景分析指南

July 23, 2026 · View on GitHub

概述

全景分析(Panorama Analysis)是本工具集的核心功能,通过关联多个数据源来提供对 Android 应用内存使用的深度洞察。定量结果先沿用大家熟悉的 dumpsys meminfo 原始行序,再让 smaps 逐行补充,而不是用另一份 TOP 列表取代 Android 汇总。全景分析能够:

  1. 逐行对账 meminfo 与 smaps:保留每个 meminfo 字段,并附加同类 smaps PSS/SwapPss 与映射证据
  2. 关联 Java 和 Native 内存:例如,将 Java Bitmap 对象与其 Native 像素内存关联
  3. 追踪 Native 内存分配:区分可追踪和未追踪的 Native 内存
  4. 整合 GPU/图形内存:包括 GraphicBuffer 和 GPU 缓存
  5. 系统内存上下文:分析系统内存压力和 Swap/zRAM 使用情况
  6. DMA-BUF 分析:追踪 GPU、Camera、Display 等硬件缓冲区内存
  7. 检测潜在问题:自动发现内存异常并给出优化建议
  8. 阈值告警:支持自定义阈值,CI/CD 集成

数据源

全景分析整合以下数据源:

数据源获取命令关键信息是否必需
meminfodumpsys meminfo <pkg>内存汇总、Native Allocations(精确 Bitmap 统计)推荐
gfxinfodumpsys gfxinfo <pkg>GPU 缓存、GraphicBuffer、帧率统计推荐
hprofam dumpheap <pkg> <path>Java 堆对象、引用链可选
smapscat /proc/<pid>/smaps详细内存映射(需要 Root)可选
proc_meminfocat /proc/meminfo系统内存状态、内存压力可选
dmabufcat /sys/kernel/debug/dma_buf/bufinfoDMA-BUF 硬件缓冲区(需要 Root)可选
zram_swap/proc/swaps + /sys/block/zram*/mm_statzRAM 压缩、Swap 使用情况可选

关键发现:Native Allocations

dumpsys meminfo 中的 Native Allocations 部分提供了精确的 Bitmap 统计:

Native Allocations
   Bitmap (malloced):       27                           6939
   Bitmap (nonmalloced):     8                          11873

这是关联 Java Bitmap 对象和 Native 内存的关键桥梁!

  • malloced: 通过 malloc 分配的 Bitmap 像素内存
  • nonmalloced: 直接分配(如 ashmem)的 Bitmap 像素内存

使用方法

一键 Dump 并分析

# 列出正在运行的应用
python3 analyze.py live --list

# 完整分析(包括 hprof)
python3 analyze.py live --package com.example.app

# 快速分析(跳过耗时的 hprof)
python3 analyze.py live --package com.example.app --skip-hprof

# 只 Dump 不分析
python3 analyze.py live --package com.example.app --dump-only -o ./dumps

一键 Dump 会自动采集

  • meminfo.txt - dumpsys meminfo 输出
  • gfxinfo.txt - dumpsys gfxinfo 输出
  • smaps.txt - /proc/pid/smaps(需要 Root)
  • proc_meminfo.txt - /proc/meminfo 系统内存
  • zram_swap.txt - zRAM/Swap 信息
  • heap.hprof - Java 堆快照(可跳过)

分析已有数据

# 分析 dump 目录(自动读取所有文件)
python3 analyze.py panorama -d ./dumps/com.example.app_20231225_120000

# 分析单独文件
python3 analyze.py panorama -m meminfo.txt -g gfxinfo.txt

# 完整分析(包括所有数据源)
python3 analyze.py panorama -m meminfo.txt -g gfxinfo.txt -H app.hprof -S smaps.txt \
    -P proc_meminfo.txt -D dmabuf_debug.txt -Z zram_swap.txt

输出格式

# 默认终端输出
python3 analyze.py panorama -d ./dump

# 输出 JSON 格式(便于自动化处理)
python3 analyze.py panorama -d ./dump --json -o result.json

# 输出 Markdown 报告
python3 analyze.py panorama -d ./dump --markdown -o report.md

阈值告警(CI/CD 集成)

# 设置内存阈值
python3 tools/panorama_analyzer.py -d ./dump \
    --threshold-pss 300 \
    --threshold-java-heap 100 \
    --threshold-native-heap 80 \
    --threshold-views 500

# Exit code: 0=正常, 1=WARNING, 2=ERROR

可用的阈值参数

参数说明单位
--threshold-pssTotal PSS 阈值MB
--threshold-java-heapJava Heap 阈值MB
--threshold-native-heapNative Heap 阈值MB
--threshold-graphicsGraphics 阈值MB
--threshold-native-untrackedNative 未追踪比例阈值%
--threshold-janky卡顿率阈值%
--threshold-viewsView 数量阈值
--threshold-activitiesActivity 数量阈值
--threshold-bitmapsBitmap 数量阈值
--threshold-bitmap-sizeBitmap 总大小阈值MB

报告解读

meminfo 主账本 + smaps 逐行旁证

同时存在两份来源时,报告先按原始顺序列出 meminfo 主表全部行。 Native HeapDalvik Heap、各类 mapping、Stack、device、UnknownTOTAL 都保持熟悉的入口;可比较的 smaps PSS/SwapPss 与映射明细附在同一行。

EGL mtrackGL mtrack 等驱动/HAL 行会标为 not-comparable,它们不出现在 /proc/<pid>/smaps 是预期边界。总量只使用显式公式 smaps_total_pss_kb + meminfo_memtrack_only_pss_kb,并报告剩余差值; 不会把 HPROF retained bytes、系统 DMA-BUF 总量或其他账本加进来。

Dalvik Details 放在主表之后用于下钻,不再作为另一份进程总量。

内存概览

📊 内存概览:
------------------------------
  Total PSS:        245.67 MB
  Java Heap:        89.34 MB
  Native Heap:      34.21 MB
  Graphics:         45.67 MB
  Code:             23.78 MB
  Stack:            1.23 MB
指标说明关注点
Total PSS进程实际占用的物理内存整体内存使用情况
Java HeapDalvik/ART 堆内存Java 对象、泄漏检测
Native HeapC/C++ 堆内存Native 代码、JNI
Graphics图形相关内存Bitmap、GPU 资源
Code代码段内存DEX、SO 库
Stack线程栈内存线程数量

系统内存上下文

────────────────────────────────────────
[ 系统内存上下文 ]
────────────────────────────────────────
系统总内存: 3579 MB (3.50 GB)
系统可用:   2099 MB (58.6%)
内存压力:   🟢 低 (LOW)
Swap 使用:  256 / 2048 MB (12.5%)
ION 内存:   169 MB
指标说明关注点
系统总内存设备物理内存总量设备规格参考
系统可用当前可分配给应用的内存<20% 需要关注
内存压力LOW/MEDIUM/HIGH/CRITICALHIGH 以上影响性能
Swap 使用zRAM/Swap 使用情况使用率高表示内存紧张
ION 内存GPU/Camera 硬件内存与 Graphics 相关

zRAM/Swap 分析

────────────────────────────────────────
[ zRAM/Swap 分析 ]
────────────────────────────────────────
Swap 总量:       2048.0 MB (1 个设备)
Swap 已用:        512.0 MB (25.0%)
zRAM 磁盘:       2048.0 MB (1 个设备)
原始数据:        1200.0 MB
压缩后数据:       280.5 MB
实际内存占用:     300.2 MB
压缩率:            4.28x
节省空间:          76.6%
节省内存:         899.8 MB
指标说明关注点
Swap 使用率Swap 空间已用比例>50% 需要关注,>80% 系统内存紧张
压缩率原始数据/压缩后数据>2x 为正常,<1.5x 数据不太可压缩
节省内存通过压缩实际节省的内存zRAM 的实际效益

DMA-BUF 分析

────────────────────────────────────────
[ DMA-BUF 分析 ]
────────────────────────────────────────
总 DMA-BUF: 156.7 MB (89 buffers)
  GPU 图形:   120.45 MB (56 buffers)
  显示:        24.00 MB (12 buffers)
  相机:         8.25 MB (15 buffers)
  视频:         4.00 MB (6 buffers)

DMA-BUF 是 Linux 内核的跨设备内存共享机制,在 Android 中用于:

  • GPU: 纹理、渲染缓冲区
  • Display: SurfaceFlinger 合成缓冲区
  • Camera: 相机预览和拍照缓冲区
  • Video: 视频解码/编码缓冲区

Bitmap 深度分析

🖼️ Bitmap 深度分析:
------------------------------
  Bitmap (malloced):     27 个    6.78 MB
  Bitmap (nonmalloced):   8 个   11.59 MB
  GPU Cache:             15.34 MB
  GraphicBuffer:         12.45 MB

Bitmap 类型

  1. malloced Bitmap

    • 通过 malloc() 分配的像素内存
    • 计入 Native Heap
    • 可通过 Bitmap.recycle() 释放
  2. nonmalloced Bitmap

    • 通过 ashmem 或其他机制直接分配
    • 不计入 Native Heap
    • 通常是硬件加速 Bitmap

图形内存

  1. GPU Cache

    • GPU 着色器缓存
    • 纹理缓存
    • 字体缓存
  2. GraphicBuffer

    • Surface 相关的图形缓冲区
    • 视频/相机预览缓冲区
    • 硬件加速渲染缓冲区

Native 内存追踪

📈 Native 内存追踪:
------------------------------
  可追踪 Native:        28.45 MB (83.2%)
  未追踪 Native:         5.76 MB (16.8%)

可追踪 Native 内存

包括:

  • Bitmap (malloced + nonmalloced)
  • Other malloced allocations
  • Other nonmalloced allocations

这些内存可以在 dumpsys meminfo 的 Native Allocations 部分看到。

未追踪 Native 内存

计算公式:未追踪 = Native Heap - 可追踪部分

可能来源:

  • 第三方 Native 库
  • JNI 代码中的直接分配
  • 系统库分配
  • 内存泄漏

重要警告:如果未追踪的 Native 内存占比过高(>30%),需要重点关注!

UI 资源统计

🎨 UI 资源统计:
------------------------------
  Views: 1,234
  ViewRootImpl: 3
  Activities: 5
  WebViews: 0
指标正常范围异常情况
Views<5000过多可能导致 UI 卡顿
ViewRootImpl1-3>5 可能存在窗口泄漏
Activities1-5>10 可能存在 Activity 泄漏
WebViews0-2每个 WebView 消耗大量内存

帧率统计

📈 帧率统计:
------------------------------
  Janky frames: 12.5%
  P50: 8ms
  P90: 16ms
  P95: 24ms
  P99: 48ms
指标良好需要优化
Janky frames<10%>20%
P50<10ms>16ms
P90<16ms>32ms
P95<24ms>48ms

异常检测

全景分析会自动检测以下异常:

1. Native 内存异常

⚠️ 未追踪的 Native 内存较大 (5.76 MB, 16.8%)
   可能原因:
   - 第三方 Native 库分配
   - JNI 直接分配
   - 内存泄漏
   建议: 使用 Native 内存分析工具(如 AddressSanitizer)进行排查

2. UI 资源异常

⚠️ Activity 数量异常 (15 个)
   正常情况下运行中的 Activity 数量应该 < 5
   可能存在 Activity 泄漏
   建议: 检查 Activity 生命周期管理

3. 帧率异常

⚠️ 卡顿帧比例过高 (25%)
   用户体验可能受到影响
   建议: 使用 Systrace/Perfetto 进行帧率分析

优化建议

Bitmap 优化

  1. 及时回收不用的 Bitmap

    if (bitmap != null && !bitmap.isRecycled()) {
        bitmap.recycle();
        bitmap = null;
    }
    
  2. 使用合适的 Bitmap 配置

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 2;  // 缩放
    options.inPreferredConfig = Bitmap.Config.RGB_565;  // 减少内存
    
  3. 使用图片加载库的内存管理

    Glide.with(context)
        .load(url)
        .override(targetWidth, targetHeight)
        .format(DecodeFormat.PREFER_RGB_565)
        .into(imageView);
    

Native 内存优化

  1. 检查 JNI 代码中的内存分配
  2. 使用 AddressSanitizer 检测泄漏
  3. 审查第三方 Native 库

UI 优化

  1. 减少 View 层级
  2. 使用 ViewStub 延迟加载
  3. 正确管理 Activity 生命周期

与其他工具配合

场景推荐工具
Java 内存泄漏LeakCanary + MAT
Native 内存泄漏AddressSanitizer
帧率优化Perfetto / Systrace
GPU 分析RenderDoc / Mali Graphics Debugger

常见问题

Q: 为什么 smaps 需要 Root?

A: /proc/<pid>/smaps 文件需要特权权限才能读取。但即使没有 smaps,meminfo + gfxinfo 仍然能提供足够的信息进行有效分析。

Q: hprof dump 失败怎么办?

A: 确保应用是 debuggable 的,或者设备已 Root。也可以使用 --skip-hprof 跳过 hprof dump,使用快速模式分析。

Q: 如何解读"未追踪 Native 内存"?

A: 未追踪的 Native 内存是指在 meminfo 的 Native Allocations 中没有记录的部分。通常来自:

  • 第三方库
  • 直接使用 mmap 分配的内存
  • 系统分配

如果这部分内存持续增长,可能存在 Native 内存泄漏。

对比分析

全景分析还支持两次 Dump 的对比分析,帮助发现内存增长问题:

# 对比两个 dump 目录
python3 analyze.py diff -b ./dump_before -a ./dump_after

# 或对比单独的 meminfo 文件
python3 analyze.py diff --before-meminfo m1.txt --after-meminfo m2.txt

对比分析会显示:

  • 各类内存的增减变化
  • View/Activity 数量变化
  • 帧率变化
  • 高亮显示增长超过阈值的项目

版本兼容性

Android 版本支持状态备注
Android 4.0-7.x✅ 完全支持部分数据源可能不可用
Android 8.0-10✅ 完全支持-
Android 11-13✅ 完全支持Scudo 分配器
Android 14-16✅ 完全支持支持 16KB 页面
Android 17+ / API 37✅ 完全支持支持 memory-limiter 证据、smaps SwapPSS/native allocator 旁证

参考资料