解析Android内存分析的指标

在 Android 系统开发中,为了精准衡量进程的内存消耗,通常会使用 VSS、RSS、PSS、USS 这四个指标。由于内存共享机制的存在,单一的"内存占用"数字往往无法真实反映进程对系统的影响,因此这四个指标提供了不同维度的观察视角。

0x00 核心含义详解

我们可以通过一个简单的模型来理解:假设进程 A 使用了 50MB 私有内存 ,并与进程 B 共享一个 20MB 的动态库

VSS (Virtual Set Size) - 虚拟耗用内存

  • 含义:进程能访问到的全部虚拟地址空间大小。
  • 包含:已分配但未实际使用的内存、映射到磁盘的文件、共享库占用的全部空间等。
  • 特点 :数值最大。它不代表真实的物理内存消耗,对于性能分析意义较小

RSS (Resident Set Size) - 实际使用物理内存

  • 含义:进程当前实际占用的物理内存(RAM)。
  • 包含 :进程的私有内存 + 共享库的全部大小
  • 缺点:存在"重复计算"。如果有 10 个进程都用了那个 20MB 的共享库,每个进程的 RSS 都会计入这 20MB。将所有进程的 RSS 相加,会远大于系统总内存。

PSS (Proportional Set Size) - 比例分配内存

  • 含义 :将共享库的大小按共享进程的数量均摊
  • 计算:私有内存 + (共享库大小 / 共享该库的进程数)。
  • 优点最客观的指标。如果将系统中所有进程的 PSS 相加,结果几乎等于系统实际消耗的总内存。它是衡量进程系统级负担的最佳标准。

USS (Unique Set Size) - 进程独占内存(最常用)

  • 含义:进程完全独占的物理内存。
  • 包含:只有该进程能访问到的 RAM 区域。
  • 优点分析内存泄露的核心指标。它表示如果杀死该进程,系统能立刻回收的内存量。

0x01 核心判断标准:为什么 USS 是"金标准"?

在分析泄漏时,我们通常遵循这个优先级:USS > PSS > RSS > VSS

  • VSS 和 RSS 的局限性:由于 RSS 包含了共享库内存,当系统其他进程加载或卸载共享库时,你的进程 RSS 可能会波动,这会产生"伪泄漏"的干扰。
  • PSS 的参考意义:PSS 能够反映你的进程对系统总内存的真实贡献。如果 PSS 持续上涨,说明你的应用正在拖慢系统。
  • USS 的决定性作用USS 只包含进程完全独占的内存。 内存泄漏本质上是进程内部的对象无法被回收,因此内存泄漏一定会直接反映在 USS 的上涨上

0x02 分析内存泄漏分析的流程

第一步:建立基准线 (Baseline)

在应用启动并进入主界面稳定后,记录当前的内存状态。

shell 复制代码
adb shell dumpsys meminfo <your_package_name>

重点记录:TOTAL PssPrivate Dirty(后者非常接近 USS)。

第二步:执行重复性操作 (Stress Test)

内存泄漏通常发生在 Activity 销毁或长生命周期对象(如 Singleton、Thread)中。执行以下操作:

  1. 进入一个怀疑有泄漏的页面,再退出。
  2. 重复上述过程 10 次以上
  3. 手动触发几次 GC(在 Android Studio Profiler 中点击小垃圾桶图标,或通过 adb shell cmd activity gc)。

第三步:对比观测

再次运行 adb shell dumpsys meminfo <your_package_name>,观察数据变化:

  • 如果 USS (Private Dirty) 阶梯式上升 :说明存在私有内存泄漏(通常是 Java 对象、Bitmap 或 Native 堆内存)。
  • 如果 PSS 上升但 USS 稳定:这种情况极少见,可能意味着你调用的系统共享资源(如某些系统服务的缓存)在增加,而不是你进程内部的泄漏。
  • 如果 PSS/USS 均不增加,但 VSS 疯狂增长:说明你在不断地申请虚拟地址空间(例如创建了大量线程,每个线程占用 1MB 虚拟栈空间,但实际还没开始使用物理内存)。
shell 复制代码
Applications Memory Usage (in Kilobytes):
Uptime: 102275 Realtime: 102275

** MEMINFO in pid 3069 [com.android.launcher3] **
                   Pss  Private  Private     Swap      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
  Native Heap    11128    11060        0        0    13796    19812    13511     2600
  Dalvik Heap     2316     2188        0        0     6620    27729     3153    24576
 Dalvik Other     2587     2264        0        0     3528                           
        Stack      736      736        0        0      740                           
       Ashmem        2        0        0        0        8                           
      Gfx dev     1244     1244        0        0     1244                           
    Other dev       36        0       36        0      284                           
     .so mmap     6076      212      128        0    54512                           
    .jar mmap     1922        0        0        0    26648                           
    .apk mmap    14824        0    13900        0    38756                           
    .ttf mmap       54        0        0        0      228                           
    .dex mmap      213        4        0        0      504                           
    .oat mmap       55        0        0        0     2044                           
    .art mmap     7794     7404        4        0    20040                           
   Other mmap     1179        4       32        0     4984                           
   EGL mtrack    40288    40288        0        0    40288                           
    GL mtrack     6104     6104        0        0     6104                           
      Unknown      466      448        0        0     1100                           
        TOTAL    97024    71956    14100        0    97024    47541    16664    27176
 
 App Summary
                       Pss(KB)                        Rss(KB)
                        ------                         ------
           Java Heap:     9596                          26660
         Native Heap:    11060                          13796
                Code:    14256                         123424
               Stack:      736                            740
            Graphics:    47636                          47636
       Private Other:     2772
              System:    10968
             Unknown:                                    9172
 
           TOTAL PSS:    97024            TOTAL RSS:   221428      TOTAL SWAP (KB):        0
 
...

0x03 针对不同类型的泄漏分析

A. Java 层泄漏 (Activity/Fragment)

  • 现象TOTAL PssJava Heap 持续增长。

  • 分析 :查看 dumpsys meminfo 最后的 Objects 部分。

    • ViewsActivities 的数量。如果你退出了页面,Activities 数量没有减少,那就是典型的 Activity 泄漏。

B. Native 层泄漏 (C++/JNI)

  • 现象Native Heap 指标持续增长,且 USS 同步上涨。
  • 分析 :如果你在 JNI 中使用了 mallocnew 但没有 free,这部分内存会体现在 Native Heap 中。

C. 共享内存/文件描述符泄漏 (SharedMemory/FD)

如果 SharedMemory 没有被正确关闭:

  • 现象USS 可能不会显著增长(如果你已经 munmap 了),但文件描述符 (FD) 会耗尽。

  • 检查方式

    bash 复制代码
    adb shell ls -l /proc/<pid>/fd | wc -l

    例如检查3069号进程(com.android.launcher3)

    shell 复制代码
    adb root
    adb shell ls -l /proc/3069/fd | wc -l
    
    # 输出
    # 82

    重复操作后,如果 FD 数量不断增加,说明你的 SharedMemoryParcelFileDescriptor 没有执行 close()

0x04 自动化检测工具推荐

虽然手动分析 dumpsys 很有帮助,但在实际开发中,建议配合以下工具:

工具 优势
LeakCanary 自动化程度最高,直接在手机端弹窗告知 Java 泄漏引用链。
Android Studio Profiler 可视化实时查看 PSS 分布,支持 Capture Heap Dump 分析堆快照。
Perfetto / Systrace 适合分析 Native 层和系统级的内存分配行为。
相关推荐
StarShip2 小时前
Android View框架概览
android·计算机图形学
summerkissyou19872 小时前
android-hardware/interfaces/automotive和hardware/libhardware/include/hardware区别
android
Evan芙2 小时前
mysql二进制部署以及多实例部署
android·数据库·mysql
走在路上的菜鸟3 小时前
Android学Dart学习笔记第二十三节 类-扩展类型
android·笔记·学习·flutter
百***78753 小时前
【技术教程】3步极速接入GPT-5.1:零门槛体验多模态AI能力
android·java·人工智能·gpt·opencv
走在路上的菜鸟4 小时前
Android学Dart学习笔记第二十一节 类-点的简写
android·笔记·学习·flutter
QQ12958455044 小时前
ThingsBoard-修改Android APP应用程序名和描述
android·物联网·iot
代码代码快快显灵4 小时前
Android项目架构深度解析
android
丐中丐9995 小时前
一个Binder通信中的多线程同步问题
android