安卓内存分析

表头 含义 分析重点
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$CodecBuffer、MediaCodec$BufferInfo 数量都在 22k+→ 明显是音视频播放 / 录制 / 推流场景在占用内存,可能是 Codec 资源没及时释放

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

步骤 1:先确认 "谁在占内存最多"
  1. 点击 Shallow Size 或 Native Size 列标题 ,按降序排序,锁定 Top 3~5 个大户(你这里已经是 byte[]、String、DirectByteBuffer 等)
  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:分析 DirectByteBuffer 和 MediaCodec 相关对象
  1. 双击 DirectByteBuffer ,看实例的引用链:
    • 来源:OkHttp 的响应缓存?图片加载的 Native Buffer?还是音视频流 Buffer?
    • 数量是否随操作不断上涨(比如反复进入播放页面后数量翻倍)?
  2. 看 MediaCodec 相关类:
    • 退出播放页面、停止推流后,这些对象数量是否下降?
    • 如果不下降 → 说明 Codec 资源、Surface、Buffer 没释放(比如没调用 release()、stop())
步骤 4:判断是否存在内存泄漏
  1. 先点顶部的 垃圾桶图标(Force GC),触发垃圾回收
  2. 重新捕获一次堆转储(Dump Java Heap)
  3. 对比两次:
    • 如果 byte[]、DirectByteBuffer、MediaCodec 相关对象数量几乎没减少 → 泄漏风险极高
    • 如果大幅减少 → 多半是临时缓存,属于正常波动
步骤 5:定位到具体代码行

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

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

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

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

  1. 图片加载 :
    • 是否用了 Glide/Picasso?有没有正确配置 skipMemoryCache、diskCacheStrategy?
    • 是否有超大图没做采样压缩(inSampleSize)?
  2. 音视频模块 :
    • 播放 / 录制结束后,是否完整调用了 MediaCodec.release()、AudioTrack.release() 等?
    • 是否复用了 Codec 而没有正确释放旧实例?
  3. 网络 / IO 缓存 :
    • OkHttp 是否配置了过大的连接池 / 缓存?
    • 是否有读写大文件后没关闭流、没释放 Buffer?
相关推荐
我不会插花弄玉28 分钟前
8. 复合查询【由浅入深-MySQL】
android·数据库·mysql
熊文豪31 分钟前
机器人开发者生态分析:行业分工变化与启元的定位
android·机器人·启元机器人
郑州光合科技余经理1 小时前
同城商城源码:商品库和订单库怎么随包交付
android·java·开发语言·后端·uni-app·php·ai编程
蒸鱼Yuzheng2 小时前
移动游戏功耗与能效归因:帧率、画质、温控和续航如何一起评估
android·性能测试·功耗优化·游戏性能·温控
hai_android3 小时前
Android 设备锁定:Kiosk Mode 实战
android·java·android jetpack
我不会插花弄玉3 小时前
9. 表的内连和外连【由浅入深-MySQL】
android·数据库·mysql
嘟哩DuliDuli3 小时前
剧本节点输入归一化:文本来源、版本与下游引用
android·人工智能·安全·ai·软件工程
high一马平川3 小时前
# SystemUI Dagger2 精读 · 第 2 章 @Inject:1200 处构造注入,和 1 处例外
android·java·kotlin
大熊的瓜地4 小时前
从0开始写android -完结篇
android