重要:而通常情景是,这个OOM不是必现的,有时运行过程中会发生,有时,同样的代码,有的手机上不出现;有的手机上会偶现。
这就加大了解决问题的难度。不过,只要遵循一定的良好的编程方式,还是有办法避免的。
1. 图片太大。
android中,系统给每个应用分配的内存是有限的,如果一个资源图片太大,加载到内存中后,占用的内存空间也会很大,(尤其是这种图片比样多的话),这样,随着程序的运行,内存不堪重负,就有可能引起OOM。
即使将background改为src,也无济于事。
例如:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/color_white" android:id="@+id/main_activity_layout"> <ImageView android:id="@+id/image_app_background" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@mipmap/imageview_main" android:scaleType="fitXY"/> </RelativeLayout>以上,是最常用的方法,但是,也有可能出现OOM的问题。
OOM错误:
java.lang.OutOfMemoryError: Failed to allocate a 9437196 byte allocation with 6950442 free bytes and 6MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:741)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:562)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1014)
at android.content.res.Resources.loadDrawableForCookie(Resources.java:3706)
at android.content.res.Resources.loadDrawable(Resources.java:3579)
at android.content.res.Resources.getDrawable(Resources.java:1852)
at android.content.res.Resources.getDrawable(Resources.java:1818)
分析:在以上xml中,直接通过android:background引用了资源文件,如果这个文件比较大,就很容易引起OOM。
我的图片大于1M,在一些低端机上很容易出现OOM,如果调成200K左右,也会偶发。最后调成30K以下,问题基本解决。
但是,仍然有一款Samsang的机子上,会偶发OOM。(解决方法:采用ImageLoader,下一篇章会介绍)。
2. 多张图片加载问题:
有时候,我们会在view中显示动态加载多张图片,可能会引起OOM问题。奇怪的是,如果加载少量图片,就不会出现类似问题。看一段伪代码(真实的有错误的代码不在这儿贴了):
for (int i = 0; i< 100; i++) { new Thread(new Runnable() { @Override public void run() { //执行图片请求,回调,然后,在回调函数中,发msg到handler。 } }).start(); } Hander的处理: private Handler mNetworkHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case Request_Success: setMyImage(msg.what); break; case Request_Fail: setMyImage(R.mipmap.default_image); break; default: break; } } };
初步解决办法:
不要在for循环内进行大量线程的创建,改用线程池,或者现有的成熟的图片加载框架。
总结:上面的场景,都是对原始图进行加载,没有进行压缩处理,而且,也没有用第三方的加载框架。很容易发生OOM。下一篇介绍采用ImageLoader可以避免这种情况发生。