背景
在上两篇文章【移动端性能专项测试之内存泄漏-原理篇】http://testingpai.com/article/1612250666032【移动端性能专项测试之内存泄漏-实战篇】http://testingpai.com/article/1596527701430给大家介绍了内存泄漏相关的知识,在Android系统中内存作为重要的资源,一直是开发及测试关注的重点,内存不足或者内存资源滥用都会导致严重的问题。本篇文章将会从底层出发给大家介绍OOM(Out Of Memory)和LMK(Low Memory Killer)等内存相关的知识。
在Android系统架构中,进程可以大体分成两类,一类是Native进程,另外一类就是Java进程
- Native进程
采用C/C++实现,本质上是linux进程,在/system/bin/目录下面的程序文件运行后都是以native进程形式存在的。
- Java进程
Android虚拟机(Dalvik或者ART)实例的linux进程,进程的入口main函数为java函数。Android虚拟机实例的宿主进程是fork()系统调用创建的linux进程,所以每一个android上的java进程实际上就是一个linux进程,只是进程中多了一个Android虚拟机实例。因此,java进程的内存分配比native进程复杂,Android系统中的应用程序基本都是java进程,如桌面、电话、联系人、状态栏等等。
Android内存限制
Android系统为每一个App设置了可使用的Heap(堆内存)大小限制,可以进入到shell环境中,找到build.prop文件
cat /system/build.prop
dalvik.vm.heapstartsize=8m
app启动后, 系统分配给它的Heap初始大小. 随着App使用可增加
dalvik.vm.heapgrowthlimit=192m
默认情况下, App可使用的Heap的最大值, 超过这个值就会产生OOM
dalvik.vm.heapsize=512m
如果App的manifest文件中配置了largeHeap属性, 如下.则App可使用的Heap的最大值为此项设定值
dalvik.vm.heaptargetutilization=0.75
当前理想的堆内存利用率. GC后, Dalvik的Heap内存会进行相应的调整, 调整到当前存活的对象的大小和 / Heap大小 接近这个选项的值, 即这里的0.75. 注意, 这只是一个参考值.
dalvik.vm.heapminfree=2m
单次Heap内存调整的最小值
dalvik.vm.heapmaxfree=8m
单次Heap内存调整的最大值
LMK(Low Memory Killer)
在用户空间中指定了一组内存临界值,当其中的某个值与进程描述中的oom_adj值在同一范围时,该进程将被Kill掉。如果你的APP某个进程需要一直保存存活,你需要保持你的进程优先级足够高,并且占用比较小,因为Low Memory Killer在工作时,同一优先级的进程会先kill那个占用最大的。性能测试时主要关注待机时的内存是不是够小。
Low Memory Killer的工作可能致系统变卡。为什么呢?因为它kill了一些进程,然而现在市面的很多APP为了保活都会自启,刚刚被kill,立刻又起来。启动占用大量内存(还有CPU),又触发Low Memory Killer。频繁的被kill和启动形成了恶性循环,so…系统变的很卡。
OOM与LMK关系
Google为什么设定当Java进程申请的Java空间超过阈值时,就抛出OOM异常?
- 为了让Android系统能同时让比较多的进程常驻内存,这样程序启动时就不用每次都重新加载到内存,能够给用户更快的响应。
- 程序发生OOM并不表示RAM不足,而是因为程序申请的java heap对象超过了虚拟机配置的heapgrowthlimit。也就是说,在RAM充足的情况下,也可能发生OOM。
如果RAM真的不足,会发生什么呢?
- 这时Android的memory killer(LMK)会起作用,当RAM所剩不多时,memory killer会杀死一些优先级比较低的进程来释放物理内存,让高优先级程序得到更多的内存。
ps:可以通过adb shell cat /proc/meminfo查看RAM的使用情况。
绕过dalvikvm heapsize的限制
对于一些大型的应用程序(比如游戏),内存使用会比较多,很容易超出虚拟机heapsize的限制,这时怎么保证程序不会因为OOM而崩溃呢?
- 创建子进程
创建一个新的进程,那么我们就可以把一些对象分配到新进程的heap上了,从而达到一个应用程序使用更多的内存的目的,当然,创建子进程会增加系统开销,而且并不是所有应用程序都适合这样做,视需求而定。 - 使用jni在native heap上申请空间
native heap的增长并不受dalvik vm heapsize的限制,只要RAM有剩余空间,程序员可以一直在native heap上申请空间,当然如果RAM快耗尽,LMK会杀进程释放RAM。大家使用一些软件时,有时候会闪退,就可能是软件在native层申请了比较多的内存导致的。
欢迎来到testingpai.com!
注册 关于