OOM问题总结

OutOfMemoryError(OOM)就是常说的内存泄露问题。为了能够使Android应用程序能够高效快速地运行,

所以Android的每个应用程序都会用一个专有的Davilk虚拟机(Android L 上谷歌使用了传闻已久的ART

来代替Dalvik)实例对象来运行,这个Davilk对象是由Zygote服务进程孵化出来的,这样的机制使每个

应用进程都只能在属于自己的进程空间中运行。Android为不同类型的进程分配了不同的内存使用上限,

也就是设置了一个阈值,当这个上限被超过时,就视为OOM,通过一定的选择策略,某些进程就会被系

统kill掉以释放内存。如果你正在开发一个应用,想知道设备的heap大小的限制是多少,比方说根据这个

值来估算自己应用的缓存大小应该限制在什么样一个水平,你可以使用ActivityManager.getMemoryClass ()

来获得一个单位为MB的整数值。

在编程中有些现象很容易造成造成内存泄露,我们应该尽量避免:
一.引用没释放造成的内存泄露
二.资源对象没关闭造成的内存泄露(比如没有关闭访问文件的输入输出流)
三.Bitmap没调用recycle(Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才它设置为null.)
四.构造Adapter时,没有使用缓存的 convertView
五.一些不良代码成内存压力(一些代码虽然不会直接造成内存泄露,但是它一直占用内存就会影响其他进程访问内存,间接造成OOM)

六.大量读取图片,比如listview或者相册,读取网络图片时,使用软引用(SoftReference),让系统能够自动的利用内存空间

解决方法:

一、处理图片时可以使用弱引用,jvm会更快的回收资源。创建Bitmap时,可以使用BitmapFactory.decodeStream(is)代替createBitmap这个方法。同时,用完的bm要尽快回收。

二、在做项目中遇到类似的问题,原因在于使用的图片在不用后未能及时回收资源。
if(!bitmap.isRecyle()){
bitmap.recycle();
System.gc();
bitmap=null;
}

三、对于一些内存非常吃紧的比如图片浏览器等应用,在平板上所需的内存更大了。因此在AndroidManifest.xml里增加了largeHeap的选项

1
2
3
4

       android:largeHeap="true"
       ...
>
这允许你的应用使用更多的heap,可以用ActivityManager.getLargeMemoryClass ()返回一个更大的可用heap size。但是这里要警告的是,千万不要因为你的应用报OOM了而使用这个选项,因为更大的heap size意味着更多的GC时间,意味着应用的性能越来越差,而且用户也会发现其他应用很有可能会内存不足。只有你需要使用很多的内存而且非常了解每一部分内存的用途,这些所需的内存都是不可或缺的,这个时候你才应该使用这个选项。

常用分析方法:

解决这类问题的关键还是要找到复现的方法,通过复现方法结合代码逻辑进行分析。我把目前为止在工作中遇到过的此类问题分为一下几类。

问题一:代码逻辑中已经实现了对资源引用的回收处理,但还是出现OOM问题

分析:工程师在设计功能的时候都是从典型用户的使用习惯触发的,由于测试人员非常规的随机的操作,导致应用始终无法走到相应的回收逻辑,旧的资源无法回收。同时,不断重复相同的操作,新的资源又被不断重复申请,最终出现OOM,应用FC。

解决办法:对于这类问题,通常的解决办法是通过修改代码逻辑规避用户进行如此操作。这样做是因为代码本身已经实现了资源回收逻辑,如果在这种非典型的用户操作过程中强行调用回收处理,很有可能会影响到后续逻辑的执行,也可能导致应用在正常用户行为下表现异常。遇到实际问题的时候,还是要评估一下做规避处理和强行调用回收处理这两种方法的改动量和风险。因为这是一个非典型的用户行为,评估后发现强行调用回收处理有上述风险,所以最后采用的规避处理,使得用户无法进行测试时的操作来解决这个问题。

问题二:代码逻辑中缺失资源回收处理导致OOM

分析:这类问题大多是因为跟图片相关的资源未做回收处理。最近就遇到一个这类问题,由于回收不完全使得相关的实例无法回收,而每次进行相同操作的时候都要重新实例化一个对象,而这个对象又绑定了一个包含了一张非常大图片的layout,layout也存在多个实例,导致内存无法释放出现OOM。

解决办法:在OnDestroy的时候做相应的回收,使得相关实例能够正常回收。

问题三:图片资源没有及时回收

分析:这类问题多是为了做代码优化以适配系统性能比较差的设备。

解决方法:当系统剩余内存比较低的时候onTrimMemory函数就会被调用,可以重新实现onTrimMemory函数,对不是正在使用的资源进行回收。重新实现OnLowMemory函数应该也是同样原理,没试过没啥发言权,大家可以自己尝试一下。

以上纯属个人观点,有些问题由于时间有点久了记得不是很清楚了,多少有些出入,但大致方向应该是没问题的。另外,跟大家分享一个小技巧。分析OOM这类问题大多数时候还是要分析hprof文件的,但是遇到屏幕分辨率比较大或是测试case比较复杂的情况,hprof文件会异常的大,获取也异常困难。使用工具抓取往往会导致应用重启或是DDMS闪退,可以尝试一下命令通过adb抓取。

                                              adb shell am dumpheap /data/data//files/dumpheap.hprof





下面的链接是关于分析OOM问题的介绍,写的非常详细,还有相关配图,便于理解。

http://www.360doc.com/content/14/0526/11/9462341_381066152.shtml

http://blog.csdn.net/chengyingzhilian/article/details/8662849


如何下载及配置MAT

http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html

小技巧:


相关连接:

http://www.dewen.io/q/1401

http://www.360doc.com/content/14/0526/11/9462341_381066152.shtml

你可能感兴趣的:(Java,Android)