Android是为移动设备而设计的,所以应该关注应用的内存使用情况。尽管Android的Dalvik虚拟机会定期执行垃圾回收操作,但这也不意味着就可以忽视应用在何时何处进行内存分配和释放。为了提供良好的用户体验,做到系统在不同应用间流畅切换,当用户和应用无交互时,避免应用不必要的内存消耗是很重要的。
尽管在开发过程中很好的遵守了《管理应用内存》(ManagingYourAppMemory)中的原则(也是应该遵守的),仍然可能会有对象泄露或引入其他的内存bug。对此的安全性,可以采取的措施就是Android代码加密,本地数据保护等一系列安全的加密技术。想详细了解的可以关注下爱加密,专业的移动应用安全智能服务提供商!唯一来确定应用使用了尽可能少的内存的方法,就是使用工具来分析应用的内存使用情况。
解析日志信息
最简单的调查应用内存使用情况的地方就是Dalvik日志信息。可以在logcat(输出信息可以在DeviceMonitor或者IDE中查看到,例如Eclipse和AndroidStudio)中找到这些日志信息。每次有垃圾回收发生,logcat会打印出带有下面信息的日志消息:
D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>
GC原因
触发垃圾回收执行的原因和垃圾回收的类型。原因主要包括:
GC_CONCURRENT
并发垃圾回收,当堆开始填满时触发来释放内存。
GC_FOR_MALLOC
堆已经满了时应用再去尝试分配内存触发的垃圾回收,这时系统必须暂停应用运行来回收内存。
GC_HPROF_DUMP_HEAP
创建HPROF文件来分析应用时触发的垃圾回收。
GC_EXPLICIT
显式垃圾回收,例如当调用(应该避免手动调用而是要让垃圾回收器在需要时主动调用)时会触发。
GC_EXTERNAL_ALLOC
这种只会在API10和更低的版本(新版本内存都只在Dalvik堆中分配)中会有。回收外部分配的内存(例如存储在本地内存或NIO字节缓冲区的像素数据)。
释放数量
执行垃圾回收后内存释放的数量。
堆状态
空闲的百分比和(活动对象的数量)/(总的堆大小)。
外部内存状态
API10和更低版本中的外部分配的内存(分配的内存大小)/(回收发生时的限制值)。
暂停时间
越大的堆的暂停时间就越长。并发回收暂停时间分为两部分:一部分在回收开始时,另一部分在回收将近结束时。
例如:
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
随着这些日志消息的增多,注意堆状态(上面例子中的3571K/9991K)的变化。如果值一直增大并且不会减小下来,那么就可能有内存泄露了。
查看堆的更新
为了得到应用内存的使用类型和时间,可以在DeviceMonitor中实时查看应用堆的更新:
1.打开DeviceMonitor。
从<sdk>/tools/路径下加载monitor工具。
2.在DebugMonitor窗口,从左边的进程列表中选择要查看的应用进程。
3.点击进程列表上面的UpdateHeap。
4.在右侧面板中选择Heap标签页。
Heap视图显示了堆内存使用的基本状况,每次垃圾回收后会更新。要看更新后的状态,点击GauseGC按钮。
图1.DeviceMonitor工具显示[1]UpdateHeap和[2]CauseGC按钮。右边的Heap标签页显示堆的情况。
跟踪内存分配
当要减少内存问题时,应该使用AllocationTracker来更好的了解内存消耗大户在哪分配。AllocationTracker不仅在查看内存的具体使用上很有用,也可以分析应用中的关键代码路径,例如滑动。
例如,在应用中滑动列表时跟踪内存分配,可以看到内存分配的动作,包括在哪些线程上分配和哪里进行的分配。这对优化代码路径来减轻工作量和改善UI流畅性都极其有用。
使用AllocationTracker:
1.打开DeviceMonitor。
从<sdk>/tools/路径下加载monitor工具。
2.在DDMS窗口,从左侧面板选择应用进程。3.在右侧面板中选择AllocationTracker标签页。4.点击StartTracking。5.执行应用到需要分析的代码路径处。6.点击GetAllocations来更新分配列表。
列表显示了所有的当前分配和512大小限制的环形缓冲区的情况。点击行可以查看分配的堆栈跟踪信息。堆栈不只显示了分配的对象类型,还显示了属于哪个线程哪个类哪个文件和哪一行。
图2.DeviceMonitor工具显示了在AllocationTracker中当前应用的内存分配和堆栈跟踪的情况。
注意:总会有一些分配是来自与DdmVmInternal和allocationtracker本身。
尽管移除掉所有严重影响性能的代码是不必要的(也是不可能的),但是allocationtracker还是可以帮助定位代码中的严重问题。例如,应用可能在每个draw操作上创建新的Paint对象。把对象改成全局变量就是一个很简单的改善性能的修改。
查看总体内存分配
为了进一步的分析,,查看应用内存中不同内存类型的分配情况,可以使用下面的adb命令:
adb shell dumpsys meminfo <package_name>
应用当前的内存分配输出列表,单位是千字节。
当查看这些信息时,应当熟悉下面的分配类型:
私有(CleanandDirty) 内存
泪,一种痛苦的雨滴,不知从什么时候开始已在我的世界下个不停。