App性能测试前需要了解的内存原理

这两天在研究性能中内存方面的一块,网上也零散看了挺多文章,写得很细但是感觉不够整体,所以这篇算是总结一下吧,当个复习资料。
那么这里个人分为两个大部分,第一部分应用内的内存管理,主要是oom的理解,GC机制和内存泄露这三个小部分;另一部分是系统级别的内存管理,包括内存共享,进程创建到LMK也就是消亡的一个简要了解,具体到某个细节,网上挺多的,就不细说了,后续看心情再补写⑧!

应用内的内存管理

一)为什么会发生OOM

Android系统为每一个运行的程序都指定了一个最大运行内存,超过这个值则会触发OOM机制,反应在界面就是闪退、crash现象,导致OOM发生的原因比如内存泄露或者是代码不考虑后果使用大量的资源,都有可能导致OOM出现的。OOM的临界值可以通过adb shell getprop | grep ‘heap’查看到
App性能测试前需要了解的内存原理_第1张图片
比如这里,heapgrowthlimit是默认单个app最大内存,heapsize则是manifest文件里设置android:largeHeap=”true”,则会使用这个最大值。

二)android里的GC机制

GC机制沿用了java的GC机制,当需要新内存去分配对象的时候而剩余不够的时候,会触发GC,把无用的对象回收掉,其中一个重要的算法便是分代式算法,这个算法把虚拟机分为年轻代、老年代和持久代,对象先分配到年轻代,然后GC多次后还存活的将会移动到老年代,老年代就不会频繁触发GC机制,一般触发频繁的都是年轻代的对象。

三)为什么会内存泄露

第二点我们知道了GC机制,那么如果GC过后程序还是没有内存,那么会发生OOM,导致GC后还是没有足够内存分配新对象的主要原因就是内存泄露了。首先要知道内存泄露也就是GC不掉的根源是生命周期长的对象持有生命周期短的对象,导致无用的对象一直无法回收。下面来看看几个典型的分类:

**静态类相关的泄露:**static对象的生命周期伴随着整个程序的生命周期,所以这块要注意不要把一些对象引用添加到static对象里面去,会造成与之关联的对象无法回收。

各种资源的释放:很多了,包括cursor的关闭,IO流的关闭,bitmap的回收等等,进行一些带有缓存的资源一定要关闭或者释放。

Handler的泄露:调用handler的delay的时候,会被认为对象是有用的,导致无法回收,还有handler开启线程去下载东西没有下载完成的时候,也会因为线程导致无法回收activity;或者使用handlerThread的时候,有延迟的方法,都会导致无法回收。其主要原因在于handler是持有activity的引用,你看主线程不是自带一个Looper然后给handler用嘛,导致有关联关系。

各种注册引用方法:比如一个常驻的后台线程处理某些时间,把当前对象注册,因为一直持有对象引用,导致这个activity一直保留,所以不用的时候需要反注册。

把对象缓存进容器内却忘记remove掉:有时候为了加快页面响应,结果缓存一些对象到容器内,结果越加越多,然后挂掉,网上有这个例子,虽然我暂时还没碰到,一块写了。

系统级别的内存管理

一) zygote的内存共享

我们知道我们的应用进程都是由zygote fork()出来的,包括系统服务和用户程序。这块的内存共享主要共享的是通用的资源内存,比如自带的主题样式,这样就避免了浪费内存空间读取一样的资源了。

二)LMK机制和oom_adj的值

Android内核有个专用的驱动low-memory-kill,当系统级别的内存不够的时候会根据oom_adj的值以及内存分配状况去kill掉某个进程,oom_adj可以在/proc/[pid]/oom_adj看到,并且这个值会随着进程的状态改变而改变,比如系统进程一般是-16,越大越容易被干掉

三) 5个进程的优先级

前台进程:当前运行的,基本不死
可见进程:界面可以见到,比如被遮挡
服务进程:进程带后台服务的,比如播放器
后台进程:点击home键,但不退出,就是后台进程了,有比较大几率会被杀
空进程:退出应用程序,还在后台保留这空进程,为的是加快启动速率,最优先杀的对象

四) 共享内存

安卓的内存的管理是分页和内存映射的,一个android程序运行的时候,会把虚拟内存通过内存映射的方式给到运行的进程,当真正要执行这块内容的时候,会通过分页的当时去分配实际内存,那么虚拟内存包括什么东西呢?
在linux环境下,通过命令

pmap -x [pid]

可以查询虚拟内存空间实例
App性能测试前需要了解的内存原理_第2张图片
App性能测试前需要了解的内存原理_第3张图片
可以看到虚拟内存的空间主要是包括这些的,代码段,堆栈,匿名共享内存,动态链接库等等。
这里又出现了一个名词,匿名共享内存,实际上这是系统开辟一个内存空间,然后映射到进程的虚拟空间,可以实现多进程共享,比如android的显示过程,处理好的surface交给surfaceFlinger服务,服务则是通过匿名共享内存的方式给缓冲区再进一步绘制我们看到的图像。
好了,总结一下,android涉及的共享内存,一个是zygote生出的子代,共享android的一些资源,一些类库,一些数据。第二个是匿名共享内存,包括surface,图形驱动音频驱动等等。

你可能感兴趣的:(App性能测试前需要了解的内存原理)