`
kingbo203
  • 浏览: 19845 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

Android 内存分析总结

阅读更多

一直没有写博客的习惯,最近觉得年纪貌似有点大了,不像以前记忆这么好,想找个方式梳理一下知识,刚好最近在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    Heap
               Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
              ------  ------  ------  ------  ------  ------  ------  ------  ------
  Native Heap      0       0       0       0       0       0    7800    7637(6)  126
  Dalvik Heap   5110(3)    0    4136    4988(3)    0       0    9168    8958(6)  210
 Dalvik Other   2850       0    2684    2772       0       0
        Stack     36       0       8      36       0       0
       Cursor    136       0       0     136       0       0
       Ashmem     12       0      28       0       0       0
    Other 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      68
      Unknown   6994(4)    0     252    6992(4)    0       0
        TOTAL  24358(1) 4188    9724   17972(2)16388    4260(2)16968   16595     336
 
 Objects
               Views:    426         ViewRootImpl:        3(8)
         AppContexts:      6(7)        Activities:        2(7)
              Assets:      2        AssetManagers:        2
       Local Binders:     64        Proxy Binders:       34
    Death Recipients:      0
     OpenSSL Sockets:      1
 
 SQL
         MEMORY_USED:   1739
  PAGECACHE_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).
  • 大小: 25 KB
分享到:
评论

相关推荐

    Android MAT 内存分析 工具

    **Android MAT内存分析工具详解** MAT(Memory Analyzer Tool...总结,MAT是Android开发中不可或缺的内存分析利器,通过深入学习和熟练运用,开发者可以有效地提高应用的性能和稳定性,避免因内存问题导致的用户流失。

    Android内存泄漏总结1

    5. 使用内存分析工具,如Android Studio的Memory Profiler,定期检查和分析应用的内存使用情况。 总的来说,理解Java和Android的内存管理机制,以及常见的内存泄漏场景,是防止和解决内存泄漏的关键。开发者应养成...

    android手机内存分配小结

    对于Android内存的监控和调试,我们可以使用adb工具进行深入分析。在没有专门的调试工具如trace32时,可以执行以下步骤: 1. 连接adb shell到设备。 2. 创建并挂载一个debugfs文件系统:`mkdir /data/debug`,然后`...

    android内存泄露测试

    ### Android内存泄露测试详解 在Android开发中,内存管理是一项至关重要的任务,不当的内存管理会导致应用运行缓慢、崩溃甚至耗尽系统资源。内存泄露是内存管理中的一个常见问题,它指的是应用程序分配了内存但未能...

    Android内存管理小结

    ### Android内存管理知识点总结 #### 一、Dalvik虚拟机及其优势 - **Dalvik虚拟机简介**:Dalvik虚拟机是Android系统的核心组件之一,它负责执行Android应用中的Java字节码。与传统的Java虚拟机(JVM)不同,Dalvik...

    android 内存分析

    ### Android 内存管理机制详解 #### 一、LowMemoryKiller 原理与实现 **LowMemoryKiller** 是 Android 内核中的一个重要组件,用于管理设备内存,特别是当系统面临内存压力时,通过合理地终止某些进程来释放内存...

    android模拟内存分配

    例如,LeakCanary和MAT(Memory Analyzer Tool)都是常用的内存分析工具,它们可以帮助开发者定位潜在的问题,并提供改进建议。 总结来说,Android系统的内存分配涉及到多种算法和策略,如不同的内存分配算法、分代...

    android模拟内存分配与回收

    总结,Android内存管理涉及到操作系统层面的内存分配算法和Java层的垃圾回收机制。循环首次适应和最佳适应算法在实现内存分配时各有优劣,而Android的垃圾回收机制通过分代策略有效管理内存。开发者应掌握这些原理,...

    深入探索Android内存优化1

    【深入探索Android内存优化1】 Android内存优化是开发者必须掌握的关键技能之一,它涉及到应用程序的稳定性和用户体验。本文将深入探讨内存优化的相关概念、工具、管理机制以及常见问题,帮助开发者构建一个完整的...

    android framework 经验总结

    这篇“Android Framework经验总结”将深入探讨这一关键领域的核心概念、主要组件以及常见开发实践。 1. **Android架构概述**: Android系统分为四个主要层次:Linux内核、系统库、Android运行时(ART)以及应用...

    android内存优化详解

    总结来说,Android内存优化主要包括理解并控制内存分配、避免内存泄漏、谨慎使用static和线程。开发者应关注对象的生命周期,确保及时释放不再使用的资源,并合理设计数据结构和引用关系,以降低内存压力。同时,...

    Android App定位和规避内存泄露方法研究

    总结来说,Android应用内存泄露是一个复杂的问题,涉及到Android内存管理机制、应用设计和代码实现等多个方面。通过上述方法,我们可以有效地检测、定位和规避内存泄露问题,从而提升Android应用的性能和稳定性。

    Android内存泄漏详解专栏

    MAT(Memory Analyzer Tool)是一款强大的内存分析工具,可以用来分析Java应用程序的内存使用情况,特别适合于检测内存泄漏问题。 #### 六、总结 Android内存泄漏是开发过程中常见的问题之一,不仅会影响应用程序的...

    Android中内存加载dex

    在Android系统中,Dalvik虚拟机...总结起来,Android中的内存加载dex是一个复杂的过程,涉及编译、优化、加载、执行等多个环节。理解这一过程有助于开发者优化应用性能,减少内存消耗,并实现如插件化等高级功能。

    android图片处理总结

    使用`BitmapFactory.Options`设置`inSampleSize`可以降低图片解析的分辨率,减少内存占用。另外,了解如何正确释放Bitmap资源以避免内存泄漏也是关键。 3. **图片显示**:ImageView是Android系统用于显示图片的组件...

    android性能优化之内存泄露

    #### 二、Android内存管理基础知识 在讨论内存泄露之前,我们需要了解一些基本概念。Android应用进程通常被分配一定量的RAM(例如:2MB到由`getMemoryClass()`或`getLargeMemoryClass()`返回的值),当内存不足时,...

    valgrind for NDK (ANDROID NDK内存检测工具)

    总结,`valgrind for NDK`是Android原生开发中不可或缺的工具,它帮助开发者在NDK环境中进行内存管理的检查和优化,提升了应用的稳定性和性能。对于任何涉及大量原生代码的Android项目,熟悉并熟练使用`valgrind`都...

Global site tag (gtag.js) - Google Analytics