安卓内存分析

表头 含义 分析重点
Class Name 类名(对象的类型) 找你自己的业务类、Activity/Fragment、Bitmap、大数组等
Allocations 该类的对象实例数量 数量异常多 → 可能重复创建或泄漏(比如 Activity 应该只有 1 个却有 5 个)
Native Size 该类对象在Native 层(C/C++)占用的内存 图片、ByteBuffer、MediaCodec 等 Native 内存大户看这里
Shallow Size 对象自身占用的内存大小(不含它引用的对象) 看单个对象本身的开销(比如 byte []、long [] 这种数组类)
Retained Size 对象自身 + 它能直接 / 间接引用到的所有对象的总内存 最关键指标:代表如果这个对象被 GC 回收,能释放多少内存

内存大户:

  1. byte[]

    • Allocations:89,643 个
    • Shallow Size:10,951,673 字节(约 10.4 MB)
    • Native Size:99,804,707 字节(约 95.2 MB)→ 说明你的 App 里有大量字节数组,且很多关联到 Native 内存(大概率是图片、音视频、网络 IO 缓存)
  2. DirectByteBuffer / DirectByteBuffer$MemoryRef

    • Allocations:33,740 + 22,500 个
    • Shallow Size:2,024,400 + 675,000 字节→ 大量直接内存缓冲区,常见于:
      • 网络请求(OkHttp/Retrofit)
      • 音视频编解码(MediaCodec)
      • 图片加载库(Glide/Picasso 用的 Native Buffer)
  3. MediaCodec$... 系列:

    • MediaCodec$BufferMap$CodecBufferMediaCodec$BufferInfo 数量都在 22k+→ 明显是音视频播放 / 录制 / 推流场景在占用内存,可能是 Codec 资源没及时释放

三、下一步具体分析步骤(按优先级)

步骤 1:先确认 "谁在占内存最多"
  1. 点击 Shallow SizeNative Size 列标题 ,按降序排序,锁定 Top 3~5 个大户(你这里已经是 byte[]StringDirectByteBuffer 等)
  2. 重点看:
    • 你自己的业务类(包名开头的类,比如 com.xxx.xxx
    • Activity/Fragment:数量是否超过预期(比如关闭页面后还残留多个实例)
    • Bitmap:如果存在,看 Shallow Size 和 Native Size(Bitmap 的 Native Size 就是图片像素内存)
步骤 2:深入分析 byte[] 这个最大户(核心操作)
  1. 双击 byte[] 这一行,展开它的实例列表
  2. 选中一个大尺寸的 byte [] 实例(按 Shallow Size 排序,找最大的几个)
  3. 右侧面板切换到 References (引用链),看:
    • 谁在引用这个 byte []?
    • 是你的业务代码?还是第三方库(Glide、OkHttp、FFmpeg、MediaCodec 等)?
    • 引用路径里有没有 静态变量(static)、单例、长生命周期对象(比如 Application、Service) ?→ 如果是静态引用持有大 byte [],这就是典型的内存泄漏
步骤 3:分析 DirectByteBufferMediaCodec 相关对象
  1. 双击 DirectByteBuffer ,看实例的引用链:
    • 来源:OkHttp 的响应缓存?图片加载的 Native Buffer?还是音视频流 Buffer?
    • 数量是否随操作不断上涨(比如反复进入播放页面后数量翻倍)?
  2. MediaCodec 相关类:
    • 退出播放页面、停止推流后,这些对象数量是否下降?
    • 如果不下降 → 说明 Codec 资源、Surface、Buffer 没释放(比如没调用 release()stop()
步骤 4:判断是否存在内存泄漏
  1. 先点顶部的 垃圾桶图标(Force GC),触发垃圾回收
  2. 重新捕获一次堆转储(Dump Java Heap)
  3. 对比两次:
    • 如果 byte[]DirectByteBufferMediaCodec 相关对象数量几乎没减少 → 泄漏风险极高
    • 如果大幅减少 → 多半是临时缓存,属于正常波动
步骤 5:定位到具体代码行

当你在引用链里找到可疑对象后:

  • 右键引用链中的某一行 → 选择 Jump to Source(跳转到源码)
  • 直接定位到:
    • 哪个类、哪一行代码创建了这个大对象
    • 哪个地方持有了不该持有的引用(比如静态集合、单例)

四、针对你当前场景的针对性建议 💡

从你的堆转储看,明显偏向 Native/IO/ 音视频场景,建议重点排查:

  1. 图片加载
    • 是否用了 Glide/Picasso?有没有正确配置 skipMemoryCachediskCacheStrategy
    • 是否有超大图没做采样压缩(inSampleSize)?
  2. 音视频模块
    • 播放 / 录制结束后,是否完整调用了 MediaCodec.release()AudioTrack.release() 等?
    • 是否复用了 Codec 而没有正确释放旧实例?
  3. 网络 / IO 缓存
    • OkHttp 是否配置了过大的连接池 / 缓存?
    • 是否有读写大文件后没关闭流、没释放 Buffer?
相关推荐
JMchen1231 小时前
第 3 篇|Android 项目结构解析与第一个界面 —— Hello, CSDN!
android·android studio·android 零基础·android 项目结构·android 界面开发
步辞3 小时前
Go语言怎么用channel做信号通知_Go语言channel信号模式教程【完整】
jvm·数据库·python
weixin_424999363 小时前
mysql行级锁失效的原因排查_检查查询条件与执行计划
jvm·数据库·python
Polar__Star3 小时前
uni-app怎么实现App端一键换肤 uni-app全局样式动态切换【实战】
jvm·数据库·python
wytraining4 小时前
快速入门 FastAPI 项目
jvm·oracle·fastapi
lhbian4 小时前
AI编程革命:Codex让脚本开发提速10倍
开发语言·汇编·jvm·c#
众少成多积小致巨4 小时前
Soong构建入门
android·go·编译器
笔夏4 小时前
【安卓学习之混淆】记录一些混淆导致闪退
android·学习
阿巴斯甜4 小时前
Kotlin高阶函数和Java 8 lambda的区别:
android
张小潇5 小时前
AOSP15 WMS/AMS系统开发 - WindowManagerService relayout调用流程详解
android