(TOP)Android内存--你需要知道的一切

一、目的

对Android中的内存有个更为具体的认识,以及在编码过程中能有意识地进行内存优化。

为什么要优化内存?

  1. 可以节约系统的内存使用,使得系统更流畅
  2. 防止OOM
  3. 防止应用被杀死(不能杜绝,只能提高存活率)

二、Android中的内存

使用命令

adb shell dumpsys meminfo <process name>

可以看到对应进程的内存占用情况,可以看到两个概念:pss和heap。

一般来说对我们有用的就是这两个值。更多关于这个表的解释可以看:https://developer.android.com/studio/profile/investigate-ram.html

pss指的是该进程实际占用的物理内存,由于Android使用一种叫做共享内存的机制,N个应用会共享系统的某些内存(比如zygote初始化的一些内存),所以pss会计算该进程按比例分配到的内存和自己私有的内存,计算结果就认为是该进程实际的内存占用。

事实上,进程还会有一些其他的内存占用,包括栈内存、一些so、apk的内存映射文件等等,所有这些构成了进程的实际物理内存占用,另外,所有的应用的PSS加起来应该是等于RAM的内存大小的。

共享内存更多查看:https://developer.android.com/training/articles/memory.html
内存映射文件更多查看:https://en.wikipedia.org/wiki/Memory-mapped_filehttp://www.cnblogs.com/zeroone/p/3721376.html

另外一个概念是Heap,这个就是堆内存,我们的对象都是分配在堆内存中的,实际上Heap还会分为Native和Dalvik,一个是C层分配的内存,一个是Dalvik虚拟机分配的内存。

TIPS:Stack内存溢出报Stackoverflow,常见的就是函数的递归调用,Dalvik Heap内存溢出报OOM异常。

三、查看内存

我们可以通过

adb shell dumpsys meminfo <process name>

看到进程的所有的内存占用快照。

PSS可以通过查看手机设置 -> RAM使用或者应用程序运行看到每个进程的实际使用内存状况。

Dalvik堆内存可以在AS的Monitor中看到。

另外,我们也可以在代码中获取这些值,详见:http://git.dev.sh.ctripcorp.com/hui.zhao/MemoryMonitor

四、内存重点

GC

GC是java中的一个概念,同样适用于Android,我们可以通过GC日志来了解GC的种类及触发机制:Android内存优化之GC的Logcat解读
GC有并行和非并行之分且耗时不会很久,但是即使是并行GC也是会在某些步骤挂起非GC线程的,所以频繁的GC可能会导致性能问题。

另外关于GC的算法详见:http://www.cnblogs.com/killmyday/archive/2013/06/12/3132518.html

GPU缓存

GPU缓存

实际检测内存的过程中,我发现PSS值是一直慢慢往上加的,原因不明,暂时认为可能是由于绘制导致的GPU缓存增加吧。

OOM

如上所说,OOM就是在Dalvik Heap满的情况下不能分配内存,系统就抛出此异常,因为是个Error类型,所以代码中不应该捕获此异常。OOM产生的原因很复杂,OOM产生的原因一般并不是抛出异常的那段代码,而是长期堆积的结果,所以Android开发过程中需要保持良好的内存使用习惯。

内存泄漏

该回收但因为有一些生命周期比较长的对象引用了它而不能回收的对象会导致内存泄漏,可以通过LeakCanary查找内存泄漏原因,或者在AS中的Heap工具中,选择Detect Actvity Leaks也可以检测Activity的内存泄漏。

五、优化内存

这里不铺开,只说一些注意点

  • 更轻量的数据结构,ArrayMap/SparseArray代替HashMap
  • 拒绝使用enum
  • Bitmap使用优化(多分辨率资源文件夹、LRU缓存)

Bitmap使用优化官方教程:http://hukai.me/android-training-course-in-chinese/graphics/displaying-bitmaps/manage-memory.html

  • onDraw中避免创建对象
  • 字符串拼接使用stringbuilder
  • 注意内存泄漏(观察者或监听器的反注册、Cursor的关闭、静态引用等)
  • onTrimMemory()的使用(后面讲)
  • 布局层级优化

onTrimMemory()

在整个应用生命周期中,如果系统内存吃紧,就会回调onTrimMemory方法,这个方法包含了若干系统内存情况。具体见https://developer.android.com/training/articles/memory.html,开发者应该在不同的回调类型中释放掉不同级别的内存。

举个栗子。

在TRIM_MEMORY_UI_HIDDEN的时候可以把ImageLoader的Bitmap内存释放掉,在TRIM_MEMORY_COMPLETE(已经威胁到进程的存活)中可以把所有的内存都释放,甚至可以退出应用,清空Activity堆栈(网易新闻在后台一段时间后切换回去的时候会重新闪屏Loading大概就是基于这个,具体没研究过)。

Low Memory Killer

Android定时执行检查,把进程优先级低的且内存占用高的进程杀死以节约内存,具体见:http://tech.hikyson.cn/2016/06/28/Android-Low-Memory-Killer/

【其他参考资料】