Dal*_*kar 8 java android out-of-memory
我有一个小的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);
}
}
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
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()我将尝试仅在方向更改的情况下解决此问题,完整的 OOM 异常解决方法超出了此答案的范围:
ImageView您可以在in中执行图像回收,因为当方向更改时,将调用onDestroy()活动。onDestroy()
您必须区分是否onDestroy()因方向变化而被调用,以执行此操作,您应该使用 is callisFinishing()
以下是演示这一点的片段:
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
WeakReference除此之外,在创建Bitmap对象时使用也会有所帮助
WeakReference<Bitmap> bm; //initialize it however you want
Run Code Online (Sandbox Code Playgroud)
**编辑**
我知道这不会有太大区别,但对我来说确实如此。android 留给我们节省内存的唯一选择是降低图像质量以及使用LruCache等其他方法。
您可以在之前添加另一行options.inSampleSize来降低图像质量以节省一些内存。
options.inPreferredConfig = Config.RGB_565;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
479 次 |
| 最近记录: |