一直没有写博客的习惯,最近觉得年纪貌似有点大了,不像以前记忆这么好,想找个方式梳理一下知识,刚好最近在ITeye上看之前一起工作过的一个大哥写的一些关于状态机的一些东西,就萌生了也写一写,记录一下的想法,第一篇就先说一说Android内存方面的一些事情吧。

很多人在进行Android开发的过程中经常会碰到内存方面的问题,比如说内存溢出,应用莫名奇妙的Crash,有时也会被客户抱怨说在第三方的应用管理软件中内存开销非常的大,这时候就需要做一些内存分析和优化的事情,本文主要来讨论内存分析的事情。

很多人一看到OOM就觉得是内存有泄漏,其实OOM并不总是由于内存泄漏所致,我个人认为,所谓泄漏是指内存无法被收回,就是说有一段逻辑会导致一些内存无法被收回,如果反复执行这段逻辑,内存会持续的增长,最后导致OOM,很多时候,OOM是我们不恰当的使用内存(尤其是图片的处理)所致,比如,在较短的时间加载了很多规格较大的图片,这方面的问题,本文也不做深入讨论(其实Google Guide有很深入的讨论,可参考   Displaying Bitmaps Efficiently 一文),我们重点来说说如何分析内存。

要分析内存,我们首先要找到衡量内存大小的一个标准,就是到底使用了多少内存,很不幸,由于Linux的内存共享机制,每个应用使用了多少内存却是笔糊涂帐,通常我们有下面几种方式来衡量:

  • VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
  • RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
  • PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
  • USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS,一般我们会用PSS来作为内存大小的衡量值,我曾经饭编译过一些内存管理软件,显示使用的内存其实就是PSS

我们可以通过命令

adb shell procrank来查看内存状况

PID      Vss      Rss      Pss      Uss  cmdline
  494   57372K   57232K   33128K   30336K  system_server
  585   46924K   46708K   25082K   23464K  com.android.systemui

通过

adb shell top来查看内存(VSS RSS)和CPU使用状况:

PID PR CPU% S  #THR     VSS     RSS PCY UID      Name
 2735  0   0% R     1   1212K    504K     shell    top
  950  0   0% S    18 661416K  25736K  fg u0_a19   android.process.media

adb shell dumpsys meminfo <package_name>

下面这个是guide里面gmail的一个dump,能够比较清晰全面的看到当前内存的使用状况,具体的含义guide里面有详细的解释,这里想说的是Dalvik Heap 和我们下面要说到的Heap moniter 中的heap size和GC 日志中 GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, 中的heap status是一样的(实际测试也是一样的),

通常我们说一个应用最多只能分配多少多少的内存实际上指的也是Dalvik Heap(在system/build.prop中定义),当应用分配的内存要超过这个定义时,就会报OOM,这个也就解释了说为什么我们通过第三方应用开我们的应用已经使用了50,甚至 60M的内存,我们的heap size只有32M,但却没有OOM,因为第三方显示的是PSS,是包含了共享内存的(这也是科学的),通过这个我们可以清楚的看到我们的内存状况是怎样的,这样内存优化也会比较有针对性。

                 Pss     Pss  Shared Private  Shared Private    Heap    Heap    HeapTotal   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free------  ------  ------  ------  ------  ------  ------  ------  ------Native Heap      0       0       0       0       0       0    7800    7637(6)  126Dalvik Heap   5110(3)    0    4136    4988(3)    0       0    9168    8958(6)  210Dalvik Other   2850       0    2684    2772       0       0Stack     36       0       8      36       0       0Cursor    136       0       0     136       0       0Ashmem     12       0      28       0       0       0Other dev    380       0      24     376       0       4.so mmap   5443(5) 1996    2584    2664(5) 5788    1996(5).apk mmap    235      32       0       0    1252      32.ttf mmap     36      12       0       0      88      12.dex mmap   3019(5) 2148       0       0    8936    2148(5)Other mmap    107       0       8       8     324      68Unknown   6994(4)    0     252    6992(4)    0       0TOTAL  24358(1) 4188    9724   17972(2)16388    4260(2)16968   16595     336ObjectsViews:    426         ViewRootImpl:        3(8)AppContexts:      6(7)        Activities:        2(7)Assets:      2        AssetManagers:        2Local Binders:     64        Proxy Binders:       34Death Recipients:      0OpenSSL Sockets:      1SQLMEMORY_USED:   1739PAGECACHE_OVERFLOW:   1164          MALLOC_SIZE:       62

通过DDMS 自带的Heap moniter也是不错的选择:

另外,有一个非常著名的Eclipse插件,叫MAT(Memory Analyzer Tool),非常的好用,尤其是它的Memory leak suspects,当你的内存一直持续的增长,增长到很大的一个值时,用MAT的Memory leak suspects,几乎 100%会指出你leak的地方在哪:


Allocation Tracker:

这个工具可以让我们在一个时间段跟踪内存的分配状况,在DDMS的Allocation Tracker:点击Start Tracking,点击几下你的应用后,再点击Get Allocations 就可以看到:

图片右下方的 at XXX 一大堆的就是一层层的调用关系,可以清晰的看到到底是谁申请了内存,申请了多少。

我们甚至还可以在代码中将将瞬态内存打印出来:


public static void printMeminfo(String where)
{
ActivityManager mgr = (ActivityManager) mContext
.getSystemService(Context.ACTIVITY_SERVICE);
int id = android.os.Process.myPid();
int[] ids = { id };
MemoryInfo[] minfo = mgr.getProcessMemoryInfo(ids);
Log.d("meminfo", where + " dalvikPrivateDirty:"
+ minfo[0].dalvikPrivateDirty + " dalvikPss:"
+ minfo[0].dalvikPss + " TotalPss: " + minfo[0].getTotalPss()
+ " TotalPrivateDirty: " + minfo[0].getTotalPrivateDirty());
}

我们在日志中经常看到有内存回收的打印:

D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms

其含义为:

D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>

其中GC Reason 有如下几个,我看到网上的一些文章,对GC Reason说的并不正确,这里我把guide中的原文一并贴上:

GC_CONCURRENT这个应该的当我们的Heap size 快要被填满的时候触发的一个并发的内存回收(A concurrent garbage collection that frees up memory as your heap begins to fill up.) ,通常GC_CONCURRENT能回收较多的内存(Heap size都快满了,用了不少的内存,应该有一部分不需要了), 下面是截取的部分此类型的回收日志:
写道
12-12 08:01:09.230: D/dalvikvm(1972): GC_CONCURRENT freed 3360K, 20% free 15422K/19052K, paused 3ms+4ms, total 46ms
12-12 08:01:10.420: D/dalvikvm(585): GC_CONCURRENT freed 11144K, 52% free 10641K/21936K, paused 3ms+4ms, total 38ms
12-12 08:01:10.890: D/dalvikvm(1336): GC_CONCURRENT freed 266K, 7% free 6321K/6736K, paused 8ms+3ms, total 36ms
12-12 08:01:10.910: D/dalvikvm(585): GC_CONCURRENT freed 1451K, 51% free 10881K/21936K, paused 3ms+3ms, total 34ms
12-12 08:01:11.000: D/dalvikvm(585): GC_CONCURRENT freed 2127K, 52% free 10616K/21936K, paused 2ms+3ms, total 22ms
12-12 08:01:11.050: D/dalvikvm(585): GC_CONCURRENT freed 1431K, 51% free 10883K/21936K, paused 2ms+2ms, total 20ms
12-12 08:01:12.900: D/dalvikvm(843): GC_FOR_ALLOC freed 3323K, 22% free 14150K/18120K, paused 25ms, total 25ms
12-12 08:01:13.630: D/dalvikvm(680): GC_CONCURRENT freed 156K, 6% free 5658K/5960K, paused 1ms+4ms, total 26ms
12-12 08:01:13.720: D/dalvikvm(680): GC_CONCURRENT freed 356K, 8% free 5812K/6312K, paused 3ms+2ms, total 19ms
GC_FOR_MALLOC这个是说我们的应用尝试去分配内存而这时候和heap已经快满了(不够用了),这个时候系统会把我们的应用停下来然后进行内存回收,通常GC_FOR_MALLOC我们的heap size会增大
(A garbage collection caused because your app attempted to allocate memory when your heap was already full, so the system had to stop your app and reclaim memory.)
12-12 07:04:10.780: D/dalvikvm(1424): GC_FOR_ALLOC freed 27K, 6% free 7332K/7768K, paused 17ms, total 17ms
12-12 07:04:10.810: D/dalvikvm(1424): GC_CONCURRENT freed <1K, 6% free 7332K/7768K, paused 3ms+1ms, total 21ms
12-12 07:04:10.850: D/dalvikvm(1424): GC_FOR_ALLOC freed <1K, 6% free 7332K/7768K, paused 22ms, total 22ms
12-12 07:04:10.870: D/dalvikvm(1424): GC_FOR_ALLOC freed 0K, 4% free 10655K/11092K, paused 19ms, total 19ms
12-12 07:04:11.950: D/dalvikvm(1972): GC_CONCURRENT freed 3295K, 19% free 15445K/18896K, paused 4ms+5ms, total 56ms
12-12 07:04:13.060: D/dalvikvm(1972): GC_CONCURRENT freed 3480K, 20% free 15365K/19004K, paused 2ms+3ms, total 54ms
12-12 07:04:15.470: D/dalvikvm(1972): GC_FOR_ALLOC freed 1763K, 20% free 15336K/19004K, paused 44ms, total 44ms
12-12 07:04:16.120: D/dalvikvm(1972): GC_FOR_ALLOC freed 3K, 20% free 15392K/19064K, paused 25ms, total 25ms
12-12 07:04:17.740: D/dalvikvm(585): GC_FOR_ALLOC freed 3557K, 20% free 17650K/21936K, paused 28ms, total 29ms
GC_HPROF_DUMP_HEAP      这个就不解释了,我们在做内存分析创建HPROF(MAT可以分析该文件)的时候会打印
(A garbage collection that occurs when you create an HPROF file to analyze your heap.)
GC_EXPLICIT这个是主动调用系统gc方法触发的GC(在DDMS 点击GC就可以看到)
An explicit garbage collection, such as when you call gc() (which you should avoid calling and instead trust the garbage collector to run when needed).
GC_EXTERNAL_ALLOC这个看原文就好,主要是回收非Dalvik heap中的数据的(以前Android的图片数据是存在native层的 。。。。)
This happens only on API level 10 and lower (newer versions allocate everything in the Dalvik heap). A garbage collection for externally allocated memory (such as the pixel data stored in native memory or NIO byte buffers).

Android 内存分析总结相关推荐

  1. Android内存分析和调优(上)

    Android内存分析和调优(上) Android内存分析和调优(上) Android内存分析工具(四):adb命令 posted on 2017-09-25 19:29 时空观察者9号 阅读(... ...

  2. Android内存分析

    最近简单学些了android内存分析,下面为一些学习笔记和整理. 一.内存数据的获取 1. 查看手机系统内存信息 adb pull /system/build.prop 打开build.prop可以查 ...

  3. Android内存分析和调优

    最近我们的android app占用了大量内存,于是领导安排做减少内存占用的工作. 要优化内存,首先要做的就是分析内存占用情况.android提供了多个工具和命令进行内存分析. 第一层 Procran ...

  4. Android内存分析工具:Memory Profiler

    一.前言  我们知道,Android系统检测到app有不再使用对象时,就会进行内存回收相关的工作. 尽管Android检测无用对象.回收内存的方法在不断改进,  但在目前所有的Android版本中,进 ...

  5. android 内存分析 名词解释,Android内存分析和调优(下)

    出自:http://www.cnblogs.com/zdwillie/p/3287150.html 最后一部分是关于native heap,.dex,/dev/other的优化.​ Native He ...

  6. android内存分析命令

    1 内存指标概念 Item 全称 含义 等价 USS Unique Set Size 物理内存 进程独占的内存 PSS Proportional Set Size 物理内存 PSS= USS+ 按比例 ...

  7. 图解Android 内存分析工具之Mat使用教程

    2019独角兽企业重金招聘Python工程师标准>>>                 感觉程序员都不太喜欢文字多的阅读,所以用图表达更简单易懂. 1.  安装 http://dow ...

  8. android 内存分析工具_Android Camera内存问题剖析

    本文通过一类 Android 机型上相机拍摄过程中的 native 内存 OOM 的问题展开,借助内存快照裁剪回捞和 Native 内存监控工具的赋能,来深入剖析此类问题. 背景 Raphael 是西 ...

  9. Android内存分析工具集【8】-TraceView

    常用的性能检测工具是traceview,集成于 Android Device Monitor 中.从Android Studio3.0开始, Android Device Monitor 被废弃,取而 ...

最新文章

  1. 利用C语言实现顺序表
  2. 第十六 django进一步了解
  3. Android之ArrayAdapter使用
  4. 编程语言python培训-0基础转行IT,编程语言应该学习Java还是Python呢?
  5. JSON为什么那样红(另有洞天)
  6. 在Sun新解决方案中心亲历虚拟化(多图)
  7. linux抓包及分析
  8. java面向对象是什么意思_java什么是面向对象
  9. WIN7镜像中增加USB3.0驱动和语言包
  10. ubuntu下格式化U盘
  11. 台式电脑显示无法连接服务器,台式电脑无法连接网络怎么办
  12. javascript当中onblur和onfocus用法
  13. 2017滴滴校招 连续最大和(DP)
  14. 微服务2——服务的注册,调用(Nacos服务注册中心+服务调用+调用负载均衡)sca-comsumersca-provider
  15. 云服务器忘记密码怎么设置?云服务器BCC实例重置密码方法【附视频】
  16. Eclipse工具工作环境配置/统一风格
  17. Excel高级图表制作①——电池图/KPI完成情况对比图/重合柱形图
  18. 洗扑克牌 (乱数排序)
  19. java中输出日历_Java打印日历表
  20. 黑盒测试与白盒测试的定义与区别

热门文章

  1. htc g1 android4.0,都以为HTC G1是世界第一部安卓手机?其实不是!
  2. selenium抓取页面可用元素css
  3. MySQL基础(尚硅谷李玉婷老师)
  4. Spring Event 业务解耦神器,刷爆了
  5. 用python画易烊千玺_易烊千玺大学英语笔记本被人捡到,本子上画了一个人,配字有点奇怪!...
  6. 记录2019年华为实习生面试
  7. 数十名员工和高管离开,谷歌支付陷入大动荡
  8. 火山中文编程 -- 实现键盘HOOK
  9. vue+SpringBoot图片预览
  10. 大学计算机二级培训新闻稿,“妙笔生花,让新闻更出彩”——计算机学院开展“如何让学院新闻更出彩”主题培训...