问题
Android开发时可以通过AndroidStudio提供的一些系列工具查看应用的内存占用,十分的方便。
但是如果是对一个成品的已安装App快速查看内存占用呢,下面简单讲两种方式。
方案一:top 命令
top
命令是一个linux下的基础命令,相信熟悉 linux 的同学都会使用。android 作为 linux 内核的系统,也具备很多 linux 下的常用指令。
首先,通过 adb shell
进入到 android 设备的内置终端。
1 | adb shell |
然后,直接执行 top
命令即可看到系统中运行的进程所占用的内存
1 | gemini:/ $ top |
以上 pid=u0_a1179
就是我们的游戏占用内存的情况, 简单解释下几个关键参数:
- PID : 进程的id
- VSS : Virtual Set Size 虚拟耗用内存(包括共享库占用的内存),即单个进程全部可访问的地址空间,器大小可能包括还尚未在内存中驻留的部分。对于确定单个进程实际内内存使用大小,VSS用处不大。
- RSS Resident Set Size 实际使用物理存储(包括共享库占用的内存),即单个进程实际占用的内存大小,RSS不太准确的地方在于它包括该进程所使用的共享库全部内存大小。对于一个共享库,可能被多个进程使用,实际该共享库只会被装入内存一次。
通过上述解释,我们可以看出,游戏占用的内存大约是 326M 左右。
以上是查看所有内存,查看指定包名还可以使用 grep 来过滤
1 | top | grep 'com.xxx.xxx.xxx.xxx' |
方案二(推荐):adb dumpsys meminfo
top
命令非常好用,但是在Android手机上,由于国产机的各种定制原因,这个命令不一定在每个设备上都会存在,所以我们还可以使用 adb dumpsys meminfo
命令来查看,这是个adb的通用命令。
adb shell dumpsys meminfo com.xxx.xxx
1 | adb shell dumpsys meminfo com.xxx.xxx -d |
下面解读一下这份数据里的关键数据。
首先了解两个概念:
私有内存(Dirty and Clean) RAM:
进程独占内存,也就是进程销毁时可以回收的内存容量。
通常 Private Dirty 内存是最重要的部分,因为只被自己进程使用。
Dirty 内存是已经被修改的内存页,因此必须常驻内存(因为没有swap)。
Clean内存是已经映射持久文件使用的内存页(例如正在被执行的代码),因此一段时间不使用的话就可以置换出去。
所有的 Dalvik Heap 和 Native Heap 都属于 Private Dirty,
与 Zygote 进程共享的 Dalvik Heap和 NativeHeap 则是共享 Dirty.
实际使用内存(PSS)
将跨进程共享页也加入进来,进行按比例计算 PSS。这样能够比较准确的表示进程占用的实际物理内存。
PASS衡量的一个优点是,你可以将所有进程的 PSS 加起来,确定所有进程占用的实际内存。这表示 PSS 是一种理想的方式,来衡量进程的 实际 RAM 占用比重,以及相对于其他进程和可用的总 RAM 而言,对 RAM 的占用情况。
通常我们需要关注的是 PASS TOTAL
和 Private Dirty
. 在某些情况下,Private Clean
和 Heap Alloc
列提供的数据也值得关注。下面列出了关于不同的内存分配(各行)需要关注的其他信息:
Dalvik Heap
Dalvik 虚拟机分配的内存。PSS Total 包含所有 Zygote 分配使用的内存,共享跨进程加权。
Private Dirty 是应用独占内存大小,包含独自分配的部分和引用进程从 Zygote 复制时被修改的 Zygote 分配的内存页。
Heap Alloc 是 Dalvik Heap 和 Native Heap 分配使用的大小,它的值比 Pss Total 和 Private Dirty 大,因为进程是从 Zygote 中复制分裂出来的,包含了进程共享的分配部分。
.so mmap & .dex mmap …mmap
这些 mmap 概括一句话就是:映射本地或虚拟机代码到使用的内存中。
.so mmap 和 .dex mmap
映射的 .so(原生) 和 .dex(Dalvik 或 ART) 代码占用的 RAM 。
Pss Total
值包括应用之间共享的平台代码。Private Clean 是应用自己的代码,通常实际映射的内存容量要大的多。此处的 RAM 只是应用已执行的代码当前需要占用的 RAM。
不过,.so mmap 具有较大的 Private Dirty RAM,这是因为在将其加载到最终地址时,对原生代码进行了修复。
.oat mmap
这是Heap 映像(Image)占用的 RAM 容量,根据多个应用共用的预加载类计算。此映像(Image)在所有应用之间共享,不受特定应用影响。
.art mmap
这是 Heap 映像(Image) 占用的 RAM 容量,根据由多个应用共用的预加载类计算,此映像(Image)在所有应用之间共享,不受特定应用影响。尽管 ART 映像(Image)包含 Object 实例,但它不会计入您的堆(Heap)占用空间。
Unknown
系统无法将其分类到其他更具体的一个项目中的 任何 RAM 页。当前,此类 RAM 页主要包含原生分配,由于地址空间布局随机化(ASLR),工具在收集此数据时无法识别这些分配。与 Dalvik Heap(堆) 相同,Unknown 的
Pass Total
考虑了与 Zygote 共享的容量,且Private Dirty
是仅由您的应用占用的未知的 RAM.TOTAL
您的进程占用的按比例分摊的内存大小(PSS)RAM 总容量,等于上述所有 PSS 字段的综合。该值表示了您的进程占用的内存容量占总体内存容量的币种,可以直接与其他进程和可用的总 RAM 进行比较。
Private Dirty
和Private Clean
合起来就是您进程中的总分配,这些分配未与其他进程共享。这些分配(尤其是 Private Dirty)的容量等于进程销毁后将释放到系统中的 RAM 容量。Private RAM 页由于已经被修改过,因此必须保留在 RAM 中(因为没有swap)。Clean RAM 页是从某个持久性文件(例如正在执行的代码)映射而来的,因此如果暂时不适用,可以将其置换出 RAM.
ViewRootImpl
您的进程中当前处于活动状态的根视图数量。每个根视图斗鱼一个窗口关联,因此该值有助于您确定与对话框或其他窗口有关的内存泄漏。
AppContexts 和 Activities
您的进程中当前处于活动状态的应用 Context 和 Activity 对象数量,该值可以帮助您快速确定发生泄漏的 Activity 对象,这些对象由于存在对其的静态引用(比较常见)而无法进行垃圾回收。这些对象往往关联了许多其他分配,因此是查找大型内存泄露的理想工具。
通过 Pss Total
我们可以看出游戏当前占用内存大约是 341M 左右(跟top
有浮动是因为游戏阶段不同)。
综上所述,推荐使用 adb dumpsys mem 的方式查看内存占用,熟悉Linux但对Android不太熟悉的,可以尝试用 top
命令。
参考资料: