关于OOM面试详解


一、什么是OOM?
    当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出的Out  of  memory异常.

Out  of  memory从名字上就可以理解,就是内存不够或者耗尽.在安卓当中,我们知道,安卓系统会为每一个APP分配一个独立的工作空间,也就是我们知道的Dalvik虚拟机空间.这样每个App都可以运行在独立的空间上,而不受其它App的影响,但是我们要知道,安卓系统中的系统为每一个Dalvik虚拟机设定了一个最大内存限制,如果,当我们当前占用的内存加上我们申请的内存资源超过了这个限制,系统就会抛出OOM错误,OOM错误在项目开发过程中经常遇到的就是BITMAP,在大图加载的时候会出现,所以说大部分的OOM问题都是和bitmap加载有关.

二、一些容易混淆的概念
     内存溢出
就是我们之前说的out  of  memory,当我们当前占用的内存加上我们申请的内存资源超过了这个限制,系统就会抛出OOM错误

     2.     内存抖动

内存抖动是因为我们在短时间内,大量的对象被创建,然后马上释放,瞬间产生的对象会严重占用内存区域.当达到一定程度,就会触发GC,(gc就是垃圾回收),回收掉你这个对象,这样你刚刚产生的对象很快就会被回收.每次分配对象占用了很少的内存,但是它们叠加在一起就会造成堆内存的压力,从而触发更多的GC,这就是内存抖动的意义.

     3.    内存泄漏

内存不在GC掌握之内了.

那么内存泄漏根本原因是GC垃圾回收机制漏掉的垃圾对象无法回收,

从而导致该垃圾对象持有的内存持续占有,这就是内存泄漏.

当内存泄漏累计到一定程度,就会造成内存溢出的现象

这三者之间,最严重的就是OOM,在开发过程当中,一提到内存,第一个映入脑海的就是OOM,其次才是内存泄漏,最后才是内存抖动.内存抖动较前两者较轻.内存溢出可以这样理解,堆内存上有些内存没有被释放从而会失去控制造成程序使用的内存越来越少,导致系统运行速度减慢,严重情况下,oom他会造成整个程序的奔溃.所以说为了提高我们APP的质量,提高用户体验,我们必须找到解决oom的办法.

三、如何解决oom
可以大致分为其它两点

1.有关于bitmap的优化
A.图片的显示
我们加载合适尺寸的图片,当显示缩略图的时候,不要去网络请求加载大图,这是一种优化机制,比如说在ListView的时候,我们会监听滑动事件,在滑动的时候,我们不去调用网络请求,而只有监听到ListView滑动停止的时候,我们再去加载大图,把图片显示到image view上

B.及时释放内存
我们知道安卓系统是有自己的回收机制的,也就是java的回收机制,他可以不定期的回收掉不使用的内存空间,大家注意,它是不定期的,你不能指定一个时间段,去回收那个内存,就是说他回收的时候肯定会有Bitmap的那个控件,那为什么我们要及时的释放内存呢?因为我们知道bitmap的构造方法都是私有的,它是通过一个BitmapFactory这个类来实例化一个bitmap的,BitmapFactory所有的生成的bitmap对象都是通过JNI这个调用方式实现的,所以说加载bitmap到内存以后,它是包含两部分内存区域的,简单的来说一部分就是Java区,一部分就是C区,而这个bitmap对象,它是由Java部分分配的,不用的时候,它当然会用Java的回收机制回收掉了,而对应的那块C的内存区域,虚拟机是不能直接回收掉的,这个只能调用底层功能来释放.所以说,我们这里来释放内存就是释放C区域的内存.

C.图片压缩
我们在开始的时候,有可能加载一张很大的大图,大图直接超过了内存分配的大小,这样肯定会导致内存溢出,这时候,我们就需要对加载Bitmap进行控制,也就是图片压缩,图片压缩有很多种例如(质量压缩,比例压缩等,在这里我说的是比例压缩),而在进行图片进行压缩的时候,需要用到一个inSampleSize 属性,就是当把图片加载到内存之前,我们需要计算一个合适的缩放比例,避免不必要的大图载入,

D.inBitmap属性
我们可以使用bitmap的inBitmap这个属性,它可以提高安卓系统在bitmap分配和释放的执行效率.

E.捕获异常
在安卓系统中,我们知道在读位图,bitmap的时候,它分给虚拟机中的图片堆栈大小,它是有限制的,所以说,为了避免应用在分配bitmap内存中出现oom异常,所以说,我们在实例化bitmap的时候,一定要对oom异常进行异常的捕获.

2.其它方面
listView:convertview/lru
我们需要使用convertview 的复用,同时对于listview中的大图控件需要使用lru机制来进行bitmap,(三级缓存机制)

避免在onDraw方法里面执行对象的创建.
我们知道,如果你频繁的在onDraw这个方法中,频繁的调用创建对象的方法,你就会使内存突然上升,这样,你在释放内存的时候,你会造成频繁的GC,这样就会造成前面说的内存抖动现象,内存抖动现象积累到一定程度也会造成oom.

谨慎使用多进程
多进程就是可以把应用中的部分组件运行在单独的进程当中,比如说App当中的定位,Webview也可以开启一个进程避免内存泄漏,

可以扩大内存占用的范围,就是说你开启了其它进程就不用占用主进程的内存,但是要注意谨慎使用,如果你的App真的没有大到一定程度,尽量少用多进程,一方面是牵扯到多进程代码更加复杂,逻辑更加的繁琐,但使用不当,不仅仅是造成内存增长,也会造成其它莫名其妙的问题.当你的应用一定需要一个后台常驻任务,你一定要开启一个进程,那么你可以考虑这个技术.