我有一个小的Android测试应用程序,其中启用largeHeap
最终会导致Out of Memory Error,因为垃圾收集永远不会被触发。
这是代码:
MainActivity.java
package com.example.oomtest;
import android.app.Activity;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.ImageView;
public class MainActivity extends Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
ImageView iv = (ImageView) findViewById(R.id.background_image);
iv.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.drawable.g01, width, height));
// System.gc();
}
public static int calculateInSampleSize(int width, int height, int reqWidth, int reqHeight)
{
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth)
{
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth)
{
inSampleSize *= 2;
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight)
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options.outWidth, options.outHeight, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
}
activity_main.xml中
<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"
tools:context=".MainActivity">
<ImageView
android:id="@+id/background_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
</RelativeLayout>
的AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.oomtest" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:largeHeap="true"
android:label="@string/app_name"
android:launchMode="singleTask"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
drawable.g01
是JPEG图片2560x1707
像素
旋转设备时会重新加载图像。启用largeHeap
后GC
永远不会被触发,方向更改序列最终会导致OOM
。禁用largeHeap
不会发生这种情况。在轮换后调用System.gc()
也可以解决问题。
启用largeHeap
时的内存消耗
启用largeHeap
和System.gc()
通话时的内存消耗
禁用largeHeap
时的内存消耗
我可以在Samsung SM-T210 API 19
设备上重现此问题。具有API 16
的相同类型的设备可以正常工作,以及API 19
Samsung GT-N7100
和Asus K01A
之类的其他设备。显然,只有特定的API /设备组合才会出现某种错误。
问题是:
System.gc()
答案 0 :(得分:1)
我将尝试仅在方向更改的情况下解决此问题,完整的OOM异常解决方法超出了此答案的范围:
您可以在ImageView
onDestroy()
中执行图像的回收,因为当方向更改时,系统会调用活动onDestroy()
。
您必须区分是否因为方向更改而调用了onDestroy()
,您应该使用is call isFinishing()
以下是演示此内容的摘要:
ImageView iv; // globally defined in class
@Override
protected void onDestroy(){
super.onDestroy();
if (isFinishing()) {
// don't do anything activity is destroying because of other reasons
}
else{ // activity is being destroyed because of orientation change
Drawable drawable = iv.getDrawable();
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
Bitmap bitmap = bitmapDrawable.getBitmap();
bitmap.recycle();
iv.setImageBitmap(null); // edited
}
}
}
创建WeakReference
对象
Bitmap
除此之外还有帮助
WeakReference<Bitmap> bm; //initialize it however you want
** 编辑 **
我知道这不会有太大的不同,但对我来说确实如此。 android为我们节省内存的唯一选择是降低图像质量以及使用LruCache等其他方法。
您可以在options.inSampleSize
之前添加另一行,以降低图像的质量以节省一些内存。
options.inPreferredConfig = Config.RGB_565;