Android内存分析和调优(上)

转载 2013年12月05日 16:29:29
最近我们的android app占用了大量内存,于是领导安排做减少内存占用的工作。
要优化内存,首先要做的就是分析内存占用情况。android提供了多个工具和命令进行内存分析。
 

第一层 Procrank

 
很粗略的,可以使用"adb shell procrank",结果类似于

PID    Vss        Rss        Pss       Uss      cmdline

......
2319 42068K 42032K 13536K 7028K com.xxx
......

该命令可以列出当前系统所有进程的内存占用情况。
PID是进程ID。
Vss是占用的虚拟内存,如果没有映射实际的内存也算进来。
Rss是占用的物理内存。是共享内存+私有内存。因为共享内存是多个进程共用的,所以存在重复计算。
Pss是占用的私有内存加上平分的共享内存。例如一块1M的共享内存被两个进程共享,那每个进程分500K。各进程的Pss相加基本等于实际被使用的物理内存,所以这个经常是最重要的参数。
Uss是私有内存。
cmdline可以看做是apk包名。

通过procrank,只能很宏观的横向比较不同的应用。如果要更细致的了解具体内存是如何使用,则需要进入

第二层 dumpsys meminfo

命令“adb shell dumpsys meminfo package.name”。在4.0 ICS(或者3.0 HoneyComb)之后的系统上,会看到类似下面的输出

                                 Shared   Private  Heap    Heap     Heap
                      Pss      Dirty      Dirty     Size     Alloc      Free
                      ------   ------    ------     ------  ------     ------
Native            16        8           16        3416   3300     79
Dalvik            3884    10592   3580    9560   9022     538
Cursor            0          0           0 
Ashmem        0           0           0 
Other dev       5110    10244   0 
.so mmap       640     1948      396 
.jar mmap      0          0           0 
.apk mmap     68        0           0 
.ttf mmap       817      0           0 
.dex mmap     411      0           0 
Other mmap   55        16         32 
Unknown        2404     660       2388 
TOTAL            13405  23468   6412    12976 12322 617

(如果使用2.3或之前的版本,结果会粗糙一些,很多都被归入了Other,但基本结构是一样的)

stacktrace上有个经常被搜到的帖子对这个格式有说明,虽然针对的是android 2.3格式,但读后非常有收获。
但仍有很多疑问没有解答,例如针对上面的例子,为什么Native heap size那么大,但Pss却那么小?占用内存比较多的Other dev是什么?Unknown又有哪些?等等。
要理解这些,需要知道这个report是如何生成的。实际上,生成report的代码是android的android_os_Debug.cpp
从中我们可以发现,上面列表的数据是由三种方式获取的:
1. Pss/Shared Dirty/Private Dirty三列是读取了/proc/process-id/smaps文件获取的。它会对每个虚拟内存块进行解析,然后生成数据。
2. Native Heap Size/Alloc/Free三列是使用C函数mallinfo得到的。
3. Dalvik Heap Size/Alloc/Free并非该cpp文件产生,而是android的Debug类生成。

后面两个Heap的获取比较简单,我唯一的疑惑是为什么有free的?我的理解是无论是c的malloc还是java的new,最后都是通过mmap系统调用进行内存分配的。而mmap必须以页的4K为单位。所以如果一次一次只需要malloc 2K,则剩下的2K是free的。如果下次再malloc 2K,可以仍然使用上次mmap剩余的2K内存。

至于smaps文件,我们可以通过adb shell cat /proc/process-id/smaps来查看(需要root)。这是个普通的linux文件,描述了进程的虚拟内存区域(vm area)的具体信息。每次mmap一般都会生成一个vm area。
在Android上,一个更加方便的命令是adb shell showmap -a process-id。

第三层 adb shell showmap

该命令也是读取smaps文件,但结果细化的具体的vm area。
该命令输出的每行表示一个vm area,列出了该vm area的start addr, end addr, Vss, Rss, Pss, shared clean, shared dirty, private clean, private dirty,object。 
第二层的dumpsys meminfo其实就是读取这些数据,然后分类(native, dalvik, .so map, etc.)统计生成。
start addr和end addr表示进程空间的起止虚拟地址。
Vss,Rss,Pss跟前面说的一样。
Object可以看做mmap的文件名。

Shared clean,按字面意思,表示共享的干净的数据。共享表示多个进程的虚拟地址可以都指向这块物理空间,表示多个进程共享的so库。为什么这里说是多个进程共享的so而不是所有的so呢?
关于so库的加载,我一直觉得是mmap带MAP_SHARED参数,但看了memory_faq,才知道是MAP_PRIVATE。如果使用showmap命令查看vm area,会发现有的so的内存都属于Shared clean,而有的so则属于private clean。前者一般是当前进程特有的so,而后者一般是通用的so。后来看了对mmap的各种参数的实验(很赞实践精神),才知道第一次以MAP_PRIVATE mmap so,内存都是private clean的。如果另外一个进程mmap了同一个so,那该vm area就变成shared clean了。

Private clean,包括该进程私有的干净的内存。包括前面说的该进程独自使用的so和进程的二进制代码段。
Clean内存的好处是在内存紧张时,可以释放物理内存。因为是clean的,所以不需要写回到disk,只需要下次读取该内存(导致缺页错误)时再从disk读入。

Private dirty,表示该进程私有的不跟disk数据一致的内存段。例如堆(heap),栈(stack),bss段。关于bss段,因为在elf文件为了节约控件没有赋值,所以在加载到内存时赋值为0,于是跟disk就不一致了。在showmap结果中,会发现几乎每个so都有一个显示位[bss]的private dirty段。数据段我估计是private clean的,因为elf文件是有初值的。

Shared dirty开始我一直搞不清楚。后来看了Dalvik vm internal这个video(slides),才明白了些。对于普通的linux进程,当父进程fork子进程时,父进程的虚拟内存区域都会”复制“一份到子进程中。这里”复制“加引号,是因为为了节省内存,也为了减少内存拷贝的时间,使用的是copy-on-write的方法。当子进程对private dirty的堆,栈,bss没有修改时,则是父子进程share这份dirty(因为跟disk没法映射)数据。如果发生改变,则会修改为private dirty。所以android有zygote进程,是所有android apps进程的父进程,在其中会加载resource等资源(下文会看到,最简单的应该也有大概5M resource,例如图片),这些资源都是只读的。具体的apps继承了这些shared dirty的数据,因为不修改它们,所以也不用分配多余的内存空间。

由于android使用的linux没有swap分区,所以dirty的数据必须常驻内存。所以dumpsys meminfo会把private dirty和shared dirty重点列出来,这也是我们优化内存的重点。

现在可以回答一个前面提到的问题,为什么Native Heap(根据mallinfo系统调用得到)很大而Native Pss(根据swaps得到)很小。我觉得这是dumpsys meminfo的一个bug。根据android_os_Debug.cpp的代码,object名字是[heap]的段被认为是native heap。这在2.3是正确的,但在4.0之后,[heap]为名字的段却很小(只有几K)。同时,我却发现有大量的[anon]的区域。我认为anon是anonymous的缩写。malloc一般是通过mmap来分配内存的,而参数是MAP_ANONYMOUS。所以我觉得这些[anon]是native heap。从大小上看,现在这些[anon]被看做是Unkown的一部分,也跟hative heap的大小差不多。

在dumpsys meminfo结果的其他值比较大的行,.so表示映射的so库(vm area行的object名称包含.so字样),.dex表示映射的.dex文件(dalvik的虚拟机二进制码),Other dev表示映射其他的/dev的(dalvik的heap也是映射到特殊的/dev上)。加上native和dalvik的heap,下次写如何具体分析这五项。

Linux内存 性能调优

内存是影响Linux性能的主要因素之一,内存资源的充足与否直接影响应用系统的使用性能。 free命令:监控Linux内存使用状况。 由上图可知,空闲内存是free+buffers+cached...
  • oDaiLiDong
  • oDaiLiDong
  • 2015年06月11日 18:38
  • 1459

JVM 内存调优 与 实际案例

堆内存设置 原理 JVM堆内存分为2块:Permanent Space 和 Heap Space。 Permanent 即 持久代(Permanent Generation),主...
  • jack85986370
  • jack85986370
  • 2016年10月24日 12:09
  • 2032

JVM内存模型与性能调优

Java是一门面向对象的编程语言,用对象来定义,描述和操作一切。对象数据存储在计算机内存中,Java的内存模型到底是个什么样子,让Java引为自豪的垃圾回收器又是如何工作的,如何针对JVM的内存管理进...
  • zshake
  • zshake
  • 2015年09月12日 20:39
  • 418

Linux性能及调优指南(翻译)之Linux内存架构

本文为IBM RedBook的Linux Performanceand Tuning Guidelines的1.2节的翻译原文地址:http://www.redbooks.ibm.com/redpap...
  • ljianhui
  • ljianhui
  • 2015年07月03日 00:36
  • 4260

JVM内存模型,以及JVM性能调优

转载批注:最近因与别人讨论问题时,问到JVM内存模型,但是苦于只知道JVM的大概内容,不知道详细,也罢,近期会逐渐有充足的自己的时间,好好整理学习学习。以下内容为转载别人的资料,个人认为写的很好,就全...
  • xzknet
  • xzknet
  • 2015年03月11日 12:03
  • 3780

<JVM调优>为什么内存过大?

首先推荐一本书《深入理解Java虚拟机——JVM高级特性与最佳实践(第2版)》,应该多读几遍。 然后分享一些这段时间我查看的一些资料 : 深入理解JVM之自动内存管理   Linux...
  • OhLog
  • OhLog
  • 2017年07月15日 11:59
  • 381

Tomcat调优总结

Tomcat 优化分为系统优化,Java虚拟机调优,Tomcat本身的优化。
  • jiangguilong2000
  • jiangguilong2000
  • 2013年10月09日 20:33
  • 53161

Storm 性能优化

最近学习storm,本文是转自同事分享的内容: 场景假设 在介绍 Storm 的性能调优方法之前,假设一个场景: 项目组部署了3台机器,计划运行且仅运行 Storm(1.0.1) + Kafka...
  • hzk_wen
  • hzk_wen
  • 2016年11月13日 23:19
  • 4595

Android内存分析和调优

最近我们的android app占用了大量内存,于是领导安排做减少内存占用的工作。 要优化内存,首先要做的就是分析内存占用情况。android提供了多个工具和命令进行内存分析。   ...
  • judyge
  • judyge
  • 2015年04月10日 06:46
  • 384

Android内存分析和调优(中)

本文转自:http://www.cnblogs.com/zdwillie/p/3259849.html 在前文中讨论了如果使用adb shell procrank, dumpsy...
  • yanjiee
  • yanjiee
  • 2014年11月27日 14:06
  • 379
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android内存分析和调优(上)
举报原因:
原因补充:

(最多只允许输入30个字)