本指南详细解释 Android 内存分析工具生成的解析结果,包括 SMAPS 解析、HPROF 分析和综合分析报告的每一项输出。帮助开发者准确理解分析结果,制定有效的内存优化策略。
python3 tools/smaps_parser.py -p <pid>
python3 tools/smaps_parser.py -f <smaps_file>python3 tools/hprof_parser.py -f <hprof_file># 分析 dump 目录
python3 tools/panorama_analyzer.py -d ./dump
# 分析单独文件
python3 tools/panorama_analyzer.py -m meminfo.txt -g gfxinfo.txt
# JSON 输出
python3 tools/panorama_analyzer.py -d ./dump --json -o result.json# 一键 Dump 并分析
python3 analyze.py live --package com.example.app
# 分析已有数据
python3 analyze.py panorama -d ./dump========================================
Android App Memory Analysis Report
Generated: 2025-07-12 22:53:18
Script Version: Universal Android Support
========================================
-
Generated: 分析报告生成时间
- 用途: 追踪分析时间点,对比历史数据
- 重要性: 确保分析数据的时效性
-
Script Version: 脚本版本信息
- 含义: "Universal Android Support" 表示支持全版本 Android
- 用途: 确保分析功能的兼容性
内存概览 / Memory Overview:
总内存使用: 49.70 MB
总交换内存: 0.00 MB
-
数值含义: 49.70 MB
- 计算方式: 所有内存类型的 PSS 总和
- 重要性: 🔴 关键指标 - 应用对系统内存的实际贡献
- 评估标准:
- 轻量应用: <50MB
- 普通应用: 50-150MB
- 重型应用: 150-300MB
- 异常: >300MB
-
问题诊断:
# 对比同类应用内存使用 # 检查是否超出应用类型的合理范围 # 分析内存增长趋势
-
下一步工具:
- 超出预期: 深入分析各内存类型分布
- 持续增长: 进行内存泄漏检测
-
数值含义: 0.00 MB
- 正常情况: Android 通常不使用传统 swap,值为 0
- 异常情况: 有数值表明内存压力大,系统启用了 swap
- 性能影响: swap 使用会显著影响性能
-
问题诊断:
# 检查系统 swap 配置 cat /proc/swaps # 监控 swap 活动 vmstat 1
Unknown (未知内存类型) : 0.793 MB
PSS: 0.793 MB
[anon:.bss] : 294 kB
[anon:linker_alloc] : 222 kB
[anon:thread signal stack] : 176 kB
[anon:bionic_alloc_small_objects] : 60 kB
[anon:System property context nodes] : 12 kB
[anon:bionic_alloc_lob] : 8 kB
[anon:arc4random data] : 8 kB
[anon:atexit handlers] : 5 kB
[anon:cfi shadow] : 4 kB
: 4 kB
SwapPSS: 0.000 MB
-
分类名称: "Unknown (未知内存类型)"
- 含义: 未能明确分类的内存区域
- 组成: 系统级内存、链接器、信号处理等
-
总大小: 0.793 MB
- 计算: 该类型所有内存区域的 PSS 总和
- 评估: 通常占总内存 2-5%,过高需要分析
- PSS 值: 0.793 MB
- 含义: 考虑共享后的实际内存占用
- 重要性: 用于内存预算计算的关键数据
[anon:.bss] : 294 kB
- 含义: 程序的 BSS 段(未初始化全局变量)
- 来源: 编译时分配的全局变量空间
- 特点: 零初始化数据段
- 问题诊断: 过大可能有过多全局变量
- 优化建议: 减少全局变量使用
[anon:linker_alloc] : 222 kB
- 含义: 动态链接器分配的内存
- 用途: 动态库加载和符号解析
- 正常范围: 通常几百KB
- 问题: 过大可能有库加载问题
[anon:thread signal stack] : 176 kB
- 含义: 线程信号处理栈
- 用途: 信号处理时的临时栈空间
- 数量: 每个线程可能有一个
- 优化: 检查线程数量是否合理
[anon:bionic_alloc_small_objects] : 60 kB
- 含义: Bionic C库小对象分配器
- 用途: 小内存块的高效分配
- Android特有: Bionic 是 Android 的 C 库
- 正常: 少量使用是正常的
其他系统内存:
- System property context nodes (12 kB): 系统属性上下文
- arc4random data (8 kB): 随机数生成器数据
- atexit handlers (5 kB): 程序退出处理函数
- cfi shadow (4 kB): 控制流完整性影子内存
- SwapPSS: 0.000 MB
- 含义: 该类型内存的交换空间使用
- 正常: Android 通常为 0
- 异常: 有值表明内存压力
Dalvik (Dalvik虚拟机运行时内存) : 3.783 MB
PSS: 3.783 MB
[anon:dalvik-main space (region space)] : 2500 kB
[anon:dalvik-zygote space] : 656 kB
[anon:dalvik-free list large object space] : 327 kB
[anon:dalvik-non moving space] : 300 kB
SwapPSS: 0.000 MB
总体评估:
- 总量: 3.783 MB
- 评估标准:
- 轻量应用: <20MB
- 普通应用: 20-80MB
- 重型应用: 80-200MB
- 异常: >200MB
- 评估标准:
主要空间详解:
[anon:dalvik-main space (region space)] : 2500 kB
- 含义: Dalvik/ART 主要堆空间
- 用途: Java 对象实例存储
- 重要性: 🔴 最重要 - 主要的 Java 内存区域
- 问题诊断:
- 持续增长: Java 内存泄漏
- 突然增大: 大对象分配或缓存
- 下一步工具:
# HPROF 分析 python3 hprof_dumper.py -pkg <package> python3 hprof_parser.py -f <hprof_file>
[anon:dalvik-zygote space] : 656 kB
- 含义: Zygote 进程共享的内存空间
- 用途: 系统类和预加载资源
- 特点: 多进程共享,节省内存
- 评估: 相对稳定,缓慢增长正常
[anon:dalvik-free list large object space] : 327 kB
- 含义: 大对象空间(>12KB 对象)
- 用途: 存储位图、大数组等
- 问题: 大对象容易导致内存碎片
- 优化建议:
- 避免创建过多大对象
- 及时释放大位图
- 使用对象池复用
[anon:dalvik-non moving space] : 300 kB
- 含义: 不可移动对象空间
- 用途: Class 对象、JNI 全局引用
- 特点: GC 时不移动,相对稳定
- 问题: 异常增长可能是 JNI 引用泄漏
Stack (线程栈内存) : 0.976 MB
PSS: 0.976 MB
[anon:stack_and_tls:22379] : 100 kB
[stack] : 60 kB
[anon:stack_and_tls:25810] : 32 kB
[anon:stack_and_tls:24523] : 32 kB
[anon:stack_and_tls:22365] : 32 kB
[anon:stack_and_tls:22241] : 32 kB
[anon:stack_and_tls:21976] : 32 kB
[anon:stack_and_tls:21970] : 32 kB
[anon:stack_and_tls:21963] : 32 kB
[anon:stack_and_tls:21962] : 32 kB
SwapPSS: 0.000 MB
线程数量统计:
- 观察: 至少 10 个线程(9个工作线程 + 1个主线程)
- 计算方式: 每个
stack_and_tls:xxxxx代表一个线程 - 评估标准:
- 正常: 5-20 个线程
- 较多: 20-50 个线程
- 过多: >50 个线程
主线程栈: [stack] : 60 kB
- 含义: 主线程的栈空间
- 正常大小: 通常 8MB 虚拟空间,实际使用几十 KB
- 问题: 过大可能有深度递归
工作线程栈: [anon:stack_and_tls:22379] : 100 kB
- 含义: 工作线程栈 + 线程本地存储
- 组成: 函数调用栈 + TLS 数据
- 大小分析:
- 100 kB: 可能有深度调用或大局部变量
- 32 kB: 正常线程栈使用
优化建议:
# 检查线程数量
adb shell "ls /proc/<pid>/task | wc -l"
# 分析线程用途
adb shell "cat /proc/<pid>/task/*/comm"
# 线程栈使用监控
watch -n 5 "cat /proc/<pid>/smaps | grep stack | wc -l"Gfx dev (图形设备内存) : 5.884 MB
PSS: 5.884 MB
/dev/kgsl-3d0 : 5884 kB
SwapPSS: 0.000 MB
总量评估:
- 5.884 MB: 图形内存使用量
- 评估标准:
- 轻量应用: <10MB
- 普通应用: 10-50MB
- 图形密集: 50-200MB
- 游戏应用: 可能更高
设备详解: /dev/kgsl-3d0 : 5884 kB
- 含义: Qualcomm GPU 图形内存设备
- 用途:
- OpenGL 纹理和缓冲区
- 渲染目标和帧缓冲
- GPU 计算内存
- 特点:
- 无法换出到存储
- 直接占用显存
- 影响图形性能
问题诊断:
- 过大原因:
- 大尺寸纹理未压缩
- 过多渲染缓冲区
- 资源未及时释放
下一步工具:
# GPU 内存详情 (如果支持)
adb shell "cat /d/kgsl/proc/<pid>/mem"
# 图形性能分析
adb shell "dumpsys gfxinfo <package> framestats"
# GPU 调试工具
# Mali Graphics Debugger, RenderDoc.so mmap (动态链接库映射内存) : 2.608 MB
PSS: 2.608 MB
/vendor/lib64/libllvm-glnext.so : 859 kB
/system/lib64/libhwui.so : 804 kB
/vendor/lib64/egl/libGLESv2_adreno.so : 235 kB
/system/lib64/libgui.so : 75 kB
/system/lib64/libsqlite.so : 70 kB
/system/lib64/libft2.so : 57 kB
/system/lib64/libandroid_runtime.so : 54 kB
/system/lib64/libharfbuzz_ng.so : 48 kB
/system/lib64/libmediandk.so : 36 kB
/system/lib64/libminikin.so : 29 kB
SwapPSS: 0.000 MB
总体评估:
- 2.608 MB: 共享库内存贡献
- 特点: PSS 值通常远小于实际库大小(因为共享)
- 效率: 体现了共享内存的优势
主要库解析:
图形相关库:
- libllvm-glnext.so (859 kB): LLVM GPU 编译器
- libGLESv2_adreno.so (235 kB): Adreno GPU OpenGL ES 驱动
- libhwui.so (804 kB): Android 硬件UI渲染库
系统核心库:
- libgui.so (75 kB): 图形用户界面库
- libandroid_runtime.so (54 kB): Android 运行时库
- libsqlite.so (70 kB): SQLite 数据库库
字体和文本:
- libft2.so (57 kB): FreeType 字体渲染
- libharfbuzz_ng.so (48 kB): 文本排版引擎
- libminikin.so (29 kB): Android 文本布局
优化分析:
# 计算共享效率
# 如果单个库实际大小是 5MB,但 PSS 只有 500KB
# 说明该库被 10 个进程共享: 5MB / 10 = 500KB
# 检查库依赖
adb shell "cat /proc/<pid>/maps | grep '\.so' | wc -l"
# 分析库加载时机
# 考虑延迟加载不常用的库.apk mmap (APK文件映射内存) : 3.048 MB
PSS: 3.048 MB
/system_ext/priv-app/Launcher3QuickStep/Launcher3QuickStep.apk : 2480 kB
/system/framework/framework-res.apk : 508 kB
/product/app/QuickSearchBox/QuickSearchBox.apk : 60 kB
SwapPSS: 0.000 MB
主应用 APK: Launcher3QuickStep.apk : 2480 kB
- 含义: 主应用 APK 的内存映射
- 包含: DEX 代码、资源文件、Native 库
- 优化: PSS 相对较低说明有一定共享
系统框架: framework-res.apk : 508 kB
- 含义: Android 系统资源包
- 共享: 被所有应用共享
- 效率: 高度共享降低了单应用成本
问题分析:
- APK 内存过大:
- 检查 APK 文件大小
- 分析资源使用效率
- 考虑资源压缩和按需加载
.art mmap (ART运行时文件映射内存) : 2.727 MB
PSS: 2.727 MB
[anon:dalvik-/system/framework/boot-framework.art] : 1537 kB
[anon:dalvik-/apex/com.android.art/javalib/boot.art] : 369 kB
[anon:dalvik-/data/dalvik-cache/arm64/app.art] : 344 kB
[anon:dalvik-/system/framework/boot-core-icu4j.art] : 230 kB
[anon:dalvik-/apex/com.android.art/javalib/boot-core-libart.art] : 97 kB
[anon:dalvik-/system/framework/boot-telephony-common.art] : 58 kB
[anon:dalvik-/system/framework/boot-voip-common.art] : 30 kB
/system/framework/arm64/boot-framework.art : 16 kB
[anon:dalvik-/apex/com.android.art/javalib/boot-bouncycastle.art] : 10 kB
[anon:dalvik-/apex/com.android.art/javalib/boot-okhttp.art] : 8 kB
SwapPSS: 0.000 MB
系统框架 ART: boot-framework.art : 1537 kB
- 含义: Android 框架的 AOT 编译代码
- 用途: 提高系统启动和运行性能
- 共享: 系统级共享,多应用受益
应用专用 ART: app.art : 344 kB
- 含义: 应用代码的 AOT 编译版本
- 用途: 提高应用启动速度和执行效率
- 生成: 应用安装或系统空闲时编译
性能影响:
- 内存换性能: ART 文件占用内存但提升执行效率
- 启动优化: 预编译代码减少启动时间
scudo heap (Scudo安全内存分配器) : 24.482 MB
PSS: 24.482 MB
[anon:scudo:primary] : 16491 kB
[anon:scudo:secondary] : 7991 kB
SwapPSS: 0.000 MB
总体评估:
- 24.482 MB: Native 内存使用的主要部分
- 重要性: 🔴 关键 - Native 内存泄漏的主要指标
- Android 版本: Android 11+ 默认使用
主要池详解: [anon:scudo:primary] : 16491 kB
- 含义: 主要内存池,用于常见大小的分配
- 特点:
- 高效的小到中等大小内存分配
- 提供安全保护机制
- 检测内存错误
[anon:scudo:secondary] : 7991 kB
- 含义: 次要内存池,用于大内存分配
- 用途: 大于主池分配粒度的内存块
- 特点: 处理不规则大小的分配
问题诊断:
-
持续增长: Native 内存泄漏
# Native 内存详细分析 adb shell "dumpsys meminfo <package> -d" # 检查 Native 内存分配 # 使用 AddressSanitizer 或 malloc hooks
-
异常大值: 检查 JNI 代码、第三方库
-
分配模式: 分析 primary vs secondary 比例
开始解析HPROF文件: com.tencent.mm_8234_20250112_143022.hprof
HPROF版本: JAVA PROFILE 1.0.3
标识符大小: 4 bytes
时间戳: 2025-01-12 14:30:22
- HPROF版本: 标准 Java 堆转储格式版本
- 标识符大小: 对象引用的字节数(32位=4字节,64位=8字节)
- 时间戳: 堆转储的确切时间
=== 内存分析完成 ===
总实例数: 2,456,789
实例总大小: 89.34 MB
总数组数: 345,678
数组总大小: 23.45 MB
总内存使用: 112.79 MB
总实例数: 2,456,789
- 含义: Java 堆中所有对象实例的总数
- 评估标准:
- 轻量应用: <100万
- 普通应用: 100-500万
- 重型应用: 500-2000万
- 异常: >2000万
- 问题诊断: 过多实例可能表明:
- 对象创建过于频繁
- 缺乏对象复用机制
- 内存泄漏导致对象累积
实例总大小: 89.34 MB
- 含义: 所有普通对象占用的内存总量
- 计算: 不包括数组的对象内存总和
- 占比: 通常占 Java 堆的 60-80%
总数组数: 345,678
- 含义: 堆中所有数组对象的数量
- 包括: 基本类型数组和对象数组
- 关注点: 大数组的内存占用
数组总大小: 23.45 MB
- 含义: 所有数组对象占用的内存
- 占比: 通常占 Java 堆的 20-40%
- 问题: 占比过高可能有大数组泄漏
总内存使用: 112.79 MB
- 计算: 实例总大小 + 数组总大小
- 对比: 应与 SMAPS 中 Dalvik 内存相近
- 差异: HPROF 只统计 Java 对象,SMAPS 包括 JVM 开销
=== TOP 20 内存占用类 (最小 0.1MB) ===
类名 实例数 总大小(MB) 平均大小(KB)
--------------------------------------------------------------------------------------
java.lang.String 234,567 15.67 0.07
android.graphics.Bitmap 1,234 12.34 10.24
com.tencent.mm.ui.ChatActivity 45 8.91 203.56
byte[] 89,012 7.23 0.08
java.util.HashMap$Node 123,456 6.78 0.06
android.view.View 45,678 5.43 0.12
com.tencent.mm.model.Message 23,456 4.32 0.19
java.lang.String - 15.67 MB
- 实例数: 234,567(数量最多)
- 平均大小: 0.07 KB(非常小)
- 分析:
- 字符串对象众多但单个很小
- 可能有字符串重复问题
- 考虑字符串常量池优化
- 优化建议:
// 使用 StringBuilder 避免频繁字符串拼接 StringBuilder sb = new StringBuilder(); // 重用字符串常量 private static final String CONSTANT = "常量字符串"; // 使用 intern() 减少重复字符串 String optimized = someString.intern();
android.graphics.Bitmap - 12.34 MB
- 实例数: 1,234(相对较少)
- 平均大小: 10.24 KB(较大)
- 分析:
- 位图是内存使用的重点
- 单个位图占用较多内存
- 需要重点优化图片使用
- 问题诊断:
# 计算位图总数是否合理 # 1,234个位图较多,检查是否有泄漏 # 平均10KB不算太大,但总量需要控制
- 优化建议:
// 及时回收位图 if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); } // 使用合适的图片格式和尺寸 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; // 缩放 options.inPreferredConfig = Bitmap.Config.RGB_565; // 减少内存
com.tencent.mm.ui.ChatActivity - 8.91 MB
- 实例数: 45(异常多)
- 平均大小: 203.56 KB(很大)
- 问题分析: 🚨 严重问题
- Activity 实例数过多(应该只有1-2个)
- 单个 Activity 过大
- 明显的 Activity 内存泄漏
- 泄漏原因:
- Static 引用持有 Activity
- Handler 未正确清理
- 监听器未注销
- 匿名内部类持有外部引用
- 下一步工具:
# 使用 LeakCanary 自动检测 # 使用 MAT (Memory Analyzer Tool) 分析引用链 # 检查 Activity 的引用路径
byte[] - 7.23 MB
- 分析: 字节数组,通常用于:
- 图片数据存储
- 网络数据缓存
- 文件读写缓冲区
- 优化: 检查是否有不必要的字节数组缓存
java.util.HashMap$Node - 6.78 MB
- 分析: HashMap 内部节点
- 实例数: 123,456(很多)
- 问题: 可能有过多的 HashMap 或单个 HashMap 过大
- 优化: 考虑使用 SparseArray 等更轻量的集合
=== TOP 10 基本类型数组内存占用 ===
数组类型 数组数量 总大小(MB) 平均大小(KB)
----------------------------------------------------------
byte[] 89,012 7.23 0.08
int[] 12,345 3.45 0.29
char[] 56,789 2.78 0.05
long[] 3,456 1.23 0.37
byte[] 数组:
- 数量: 89,012(最多)
- 总大小: 7.23 MB
- 平均大小: 0.08 KB(很小)
- 用途推测:
- 图片解码缓冲区
- 网络数据包
- 字符串的字节表示
- 优化: 考虑对象池复用小字节数组
int[] 数组:
- 平均大小: 0.29 KB(相对较大)
- 可能用途: 像素数据、坐标数组、索引数组
char[] 数组:
- 与字符串相关: char[]是String内部存储
- 数量大: 与String数量对应
long[] 数组:
- 平均最大: 0.37 KB
- 可能用途: 时间戳数组、ID数组
=== 字符串内存统计 ===
字符串实例数: 234,567
字符串总大小: 15.67 MB
平均字符串大小: 70.12 bytes
字符串密度: 15.67MB / 112.79MB = 13.9%
- 评估: 字符串占比适中
- 优化潜力: 仍有优化空间
平均大小: 70.12 bytes
- 分析: 中等长度字符串
- 对比:
- <50 bytes: 短字符串,考虑常量池
- 50-200 bytes: 中等长度,正常
-
200 bytes: 长字符串,检查是否必要
优化策略:
// 1. 字符串常量池
private static final String[] COMMON_STRINGS = {
"常用字符串1", "常用字符串2"
};
// 2. StringBuilder 复用
private final StringBuilder mStringBuilder = new StringBuilder();
// 3. 字符串缓存
private final LruCache<String, String> mStringCache =
new LruCache<>(100);══════════════════════════════════════════════════════════════════════════════
Android 应用内存全景分析报告
══════════════════════════════════════════════════════════════════════════════
com.android.systemui
2025-01-15 10:30:22
══════════════════════════════════════════════════════════════════════════════
────────────────────────────────────────
[ 内存概览 ]
────────────────────────────────────────
Total PSS: 142.08 MB
Java Heap: 31.85 MB
Native Heap: 44.76 MB
Graphics: 29.27 MB
Code: 15.29 MB
Stack: 1.11 MB
Total PSS: 142.08 MB
- 来源: dumpsys meminfo 的 TOTAL PSS
- 包含: Java堆 + Native堆 + Graphics + Code + Stack + 其他
- 评估: 是进程对系统内存贡献的最准确指标
各内存分类占比计算:
- 计算: 各分类 / Total PSS * 100%
- 评估标准:
- Java Heap: 20-40% 正常
- Native Heap: 20-40% 正常
- Graphics: 10-30% 正常(图形密集型应用可能更高)
- Code: 5-15% 正常
- 分析: 通过占比可以快速判断应用内存使用的特点
────────────────────────────────────────
[ Native 内存追踪 ]
────────────────────────────────────────
Native Heap PSS: 44.76 MB (100%)
├── 可追踪: 39.00 MB (87.1%)
│ ├── Bitmap: 18.37 MB (41.0%)
│ ├── Malloced: 15.43 MB (34.5%)
│ └── NonMalloced: 5.20 MB (11.6%)
└── 未追踪: 5.76 MB (12.9%)
Java Heap: 31.85 MB
- 评估: 占比合理
- 关注: 是否有持续增长趋势,使用 HPROF 深入分析
图形内存: 29.27 MB
- 评估: 图形内存使用
- 问题: 可能的 UI 过度绘制或纹理泄漏
- 优化: 检查位图使用和 GPU 资源管理
Native 内存追踪:
- 可追踪 (87.1%): 在 dumpsys meminfo Native Allocations 中有记录
- 未追踪 (12.9%): 第三方库、JNI 直接分配等
- 警告阈值: 未追踪占比 >30% 需要关注
💡 优化建议:
------------------------------
⚠️ [Java堆内存] Java堆内存使用量较大 (89.3MB),建议检查内存泄漏
ℹ️ [字符串优化] 字符串占用 15.7MB,建议优化字符串使用,考虑使用StringBuilder或字符串常量池
ℹ️ [图形内存] 图形内存使用较高 (45.7MB),检查位图缓存和GPU内存使用
ℹ️ [Native内存] Native堆内存使用较高 (34.2MB),检查JNI代码和第三方库
🔴 高优先级: Java堆内存检查
# 1. 执行内存泄漏检测
python3 hprof_dumper.py -pkg <package> -o before/
# 执行操作
python3 hprof_dumper.py -pkg <package> -o after/
# 对比分析
# 2. 使用自动检测工具
# 集成 LeakCanary
implementation 'com.squareup.leakcanary:leakcanary-android:2.12'
# 3. MAT 工具分析
# 下载 Eclipse Memory Analyzer Tool
# 导入 HPROF 文件分析引用链🟡 中优先级: 字符串优化
// 1. 字符串常量池使用
private static final String CACHED_STRING = "常用字符串";
// 2. StringBuilder 复用
private final StringBuilder mBuilder = new StringBuilder(256);
// 3. 字符串缓存
private final Map<String, String> mStringCache = new HashMap<>();🟢 低优先级: 图形内存优化
// 1. 位图回收
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap = null;
}
// 2. 图片加载优化
Glide.with(context)
.load(url)
.override(targetWidth, targetHeight)
.format(DecodeFormat.PREFER_RGB_565)
.into(imageView);
// 3. LRU 缓存
private final LruCache<String, Bitmap> mBitmapCache =
new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount();
}
};com.example.MainActivity: 5 instances, 12.3 MB
特征: Activity 实例数 > 2 原因: Static 引用、Handler、监听器 处理:
// 1. 避免 static 引用 Activity
// 错误
private static Context sContext;
// 正确
private static WeakReference<Context> sContextRef;
// 2. Handler 正确使用
private static class MyHandler extends Handler {
private final WeakReference<Activity> mActivityRef;
MyHandler(Activity activity) {
mActivityRef = new WeakReference<>(activity);
}
}
// 3. 监听器注销
@Override
protected void onDestroy() {
eventBus.unregister(this);
super.onDestroy();
}java.util.ArrayList: 50,000 instances, 25.6 MB
特征: 集合实例数异常多 原因: 集合未清理、缓存无限增长 处理:
// 1. 使用 WeakHashMap
Map<Key, Value> cache = new WeakHashMap<>();
// 2. LRU 缓存
LruCache<String, Object> cache = new LruCache<>(maxSize);
// 3. 定期清理
if (cache.size() > MAX_SIZE) {
cache.clear();
}android.graphics.Bitmap: 2 instances, 48.5 MB average: 24.25 MB
特征: 单个对象异常大 处理:
// 1. 图片压缩
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inPreferredConfig = Bitmap.Config.RGB_565;
// 2. 分片加载大图
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(inputStream, false);
Bitmap region = decoder.decodeRegion(rect, options);byte[]: 10 instances, 32.1 MB average: 3.21 MB
处理:
// 1. 流式处理
try (InputStream is = new FileInputStream(file);
OutputStream os = new FileOutputStream(output)) {
byte[] buffer = new byte[8192]; // 小缓冲区
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
}
// 2. 对象池复用
public class ByteArrayPool {
private final Queue<byte[]> pool = new ConcurrentLinkedQueue<>();
public byte[] acquire(int size) {
byte[] array = pool.poll();
if (array == null || array.length < size) {
array = new byte[size];
}
return array;
}
public void release(byte[] array) {
pool.offer(array);
}
}# 大量小对象
java.lang.Object: 1,000,000 instances, average: 24 bytes
# 内存使用不连续
Virtual: 512 MB, RSS: 128 MB (25% utilization)// 1. 对象池
public class ObjectPool<T> {
private final Queue<T> pool = new ArrayDeque<>();
private final Factory<T> factory;
public T acquire() {
T item = pool.poll();
return item != null ? item : factory.create();
}
public void release(T item) {
reset(item);
pool.offer(item);
}
}
// 2. 内存预分配
List<Object> preAllocated = new ArrayList<>(expectedSize);
// 3. 减少临时对象
// 错误:频繁创建对象
for (int i = 0; i < 1000; i++) {
String temp = "prefix" + i + "suffix";
}
// 正确:复用 StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.setLength(0);
sb.append("prefix").append(i).append("suffix");
String result = sb.toString();
}- 应用级分析: dumpsys meminfo 解释指南
- 系统级分析: /proc/meminfo 解释指南
- 进程级概览: showmap 解释指南
- 详细映射分析: smaps 解释指南
- Eclipse MAT: Memory Analyzer Tool
- VisualVM: Java 性能分析
- YourKit: 商业 Java profiler
- AddressSanitizer: ASan 内存错误检测
- Valgrind: Linux 内存分析
- Heaptrack: 堆内存追踪
- analyze.py: 入口脚本,支持 live dump 和 panorama 分析
- panorama_analyzer.py: 全景分析核心
- hprof_parser.py: HPROF 文件解析
- smaps_parser.py: SMAPS 文件解析
- meminfo_parser.py: dumpsys meminfo 解析
- gfxinfo_parser.py: dumpsys gfxinfo 解析
- zram_parser.py: zRAM/Swap 分析
- diff_analyzer.py: 对比分析
本指南聚焦于分析结果的解读与诊断逻辑。
关于团队教学流程、报告模板和 Android 16 兼容检查,请统一使用:
推荐配合方式:
- 本文用于读懂输出、定位问题。
teaching_playbook.md用于培训执行流程、监控脚本基线和评审检查项。- 基线与复验必须使用同一采集策略,避免口径漂移。