一直没有写博客的习惯,最近觉得年纪貌似有点大了,不像以前记忆这么好,想找个方式梳理一下知识,刚好最近在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
GC_CONCURRENT能回收较多的内存(
Heap size都快满了,用了不少的内存,应该有一部分不需要了),
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
GC_FOR_MALLOC
我们的heap size会增大
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: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
GC_EXPLICIT
gc()
(which you should avoid calling and instead trust the garbage collector to run when needed).GC_EXTERNAL_ALLOC
相关推荐
**Android MAT内存分析工具详解** MAT(Memory Analyzer Tool...总结,MAT是Android开发中不可或缺的内存分析利器,通过深入学习和熟练运用,开发者可以有效地提高应用的性能和稳定性,避免因内存问题导致的用户流失。
5. 使用内存分析工具,如Android Studio的Memory Profiler,定期检查和分析应用的内存使用情况。 总的来说,理解Java和Android的内存管理机制,以及常见的内存泄漏场景,是防止和解决内存泄漏的关键。开发者应养成...
对于Android内存的监控和调试,我们可以使用adb工具进行深入分析。在没有专门的调试工具如trace32时,可以执行以下步骤: 1. 连接adb shell到设备。 2. 创建并挂载一个debugfs文件系统:`mkdir /data/debug`,然后`...
### Android内存泄露测试详解 在Android开发中,内存管理是一项至关重要的任务,不当的内存管理会导致应用运行缓慢、崩溃甚至耗尽系统资源。内存泄露是内存管理中的一个常见问题,它指的是应用程序分配了内存但未能...
### Android内存管理知识点总结 #### 一、Dalvik虚拟机及其优势 - **Dalvik虚拟机简介**:Dalvik虚拟机是Android系统的核心组件之一,它负责执行Android应用中的Java字节码。与传统的Java虚拟机(JVM)不同,Dalvik...
### Android 内存管理机制详解 #### 一、LowMemoryKiller 原理与实现 **LowMemoryKiller** 是 Android 内核中的一个重要组件,用于管理设备内存,特别是当系统面临内存压力时,通过合理地终止某些进程来释放内存...
例如,LeakCanary和MAT(Memory Analyzer Tool)都是常用的内存分析工具,它们可以帮助开发者定位潜在的问题,并提供改进建议。 总结来说,Android系统的内存分配涉及到多种算法和策略,如不同的内存分配算法、分代...
总结,Android内存管理涉及到操作系统层面的内存分配算法和Java层的垃圾回收机制。循环首次适应和最佳适应算法在实现内存分配时各有优劣,而Android的垃圾回收机制通过分代策略有效管理内存。开发者应掌握这些原理,...
【深入探索Android内存优化1】 Android内存优化是开发者必须掌握的关键技能之一,它涉及到应用程序的稳定性和用户体验。本文将深入探讨内存优化的相关概念、工具、管理机制以及常见问题,帮助开发者构建一个完整的...
这篇“Android Framework经验总结”将深入探讨这一关键领域的核心概念、主要组件以及常见开发实践。 1. **Android架构概述**: Android系统分为四个主要层次:Linux内核、系统库、Android运行时(ART)以及应用...
总结来说,Android内存优化主要包括理解并控制内存分配、避免内存泄漏、谨慎使用static和线程。开发者应关注对象的生命周期,确保及时释放不再使用的资源,并合理设计数据结构和引用关系,以降低内存压力。同时,...
总结来说,Android应用内存泄露是一个复杂的问题,涉及到Android内存管理机制、应用设计和代码实现等多个方面。通过上述方法,我们可以有效地检测、定位和规避内存泄露问题,从而提升Android应用的性能和稳定性。
MAT(Memory Analyzer Tool)是一款强大的内存分析工具,可以用来分析Java应用程序的内存使用情况,特别适合于检测内存泄漏问题。 #### 六、总结 Android内存泄漏是开发过程中常见的问题之一,不仅会影响应用程序的...
在Android系统中,Dalvik虚拟机...总结起来,Android中的内存加载dex是一个复杂的过程,涉及编译、优化、加载、执行等多个环节。理解这一过程有助于开发者优化应用性能,减少内存消耗,并实现如插件化等高级功能。
使用`BitmapFactory.Options`设置`inSampleSize`可以降低图片解析的分辨率,减少内存占用。另外,了解如何正确释放Bitmap资源以避免内存泄漏也是关键。 3. **图片显示**:ImageView是Android系统用于显示图片的组件...
#### 二、Android内存管理基础知识 在讨论内存泄露之前,我们需要了解一些基本概念。Android应用进程通常被分配一定量的RAM(例如:2MB到由`getMemoryClass()`或`getLargeMemoryClass()`返回的值),当内存不足时,...
总结,`valgrind for NDK`是Android原生开发中不可或缺的工具,它帮助开发者在NDK环境中进行内存管理的检查和优化,提升了应用的稳定性和性能。对于任何涉及大量原生代码的Android项目,熟悉并熟练使用`valgrind`都...