web-dev-qa-db-ja.com

Android OutOfMemoryError :?

アプリの1つでOutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB)を散発的に取得しています。これを診断するにはどうすればよいですか?

  01-09 10:32:02.079: E/dalvikvm(8077): Out of memory: Heap Size=49187KB, Allocated=41957KB, Limit=49152KB
  01-09 10:32:02.079: E/dalvikvm(8077): Extra info: Footprint=48611KB, Allowed Footprint=49187KB, Trimmed=7852KB
  01-09 10:32:02.079: D/skia(8077): --- decoder->decode returned false
  01-09 10:32:02.079: D/AndroidRuntime(8077): Shutting down VM
  01-09 10:32:02.079: W/dalvikvm(8077): threadid=1: thread exiting with uncaught exception (group=0x40a97228)
  01-09 10:32:02.079: E/AndroidRuntime(8077): FATAL EXCEPTION: main
  01-09 10:32:02.079: E/AndroidRuntime(8077): Java.lang.OutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.Java:486)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.graphics.drawable.Drawable.createFromResourceStream(Drawable.Java:773)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.content.res.Resources.loadDrawable(Resources.Java:2044)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.content.res.Resources.getDrawable(Resources.Java:675)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.view.View.setBackgroundResource(View.Java:11776)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at com.blsk.bigtoss.ImageLoader.DisplayImage(ImageLoader.Java:81)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at com.blsk.bigtoss.MatchActivity$MatchAsyncTask.onPostExecute(MatchActivity.Java:1768)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.AsyncTask.finish(AsyncTask.Java:602)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.AsyncTask.access$600(AsyncTask.Java:156)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.Java:615)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.Handler.dispatchMessage(Handler.Java:99)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.Looper.loop(Looper.Java:156)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.app.ActivityThread.main(ActivityThread.Java:4987)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Java.lang.reflect.Method.invokeNative(Native Method)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Java.lang.reflect.Method.invoke(Method.Java:511)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:784)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:551)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at dalvik.system.NativeStart.main(Native Method)
  01-09 10:32:02.099: E/EmbeddedLogger(1612): App crashed! Process: com.blsk.bigtoss
  01-09 10:32:02.099: E/EmbeddedLogger(1612): App crashed! Package: com.blsk.bigtoss v6 (1.2)
  01-09 10:32:02.129: E/EmbeddedLogger(1612): Application Label: Cricket

これはそれが起こっている行です:

LinearLayout resultMatchHeaderContainer = new LinearLayout(activity); 

if (!resultImagePath.equals("")) {   
    imageLoader.DisplayImage(resultImagePath,resultMatchHeaderContainer, -1,modifiedHeight, R.drawable.matches_placeholder_result2x);
} else {
    try {
        resultMatchHeaderContainer.setBackgroundResource(R.drawable.matches_placeholder_result2x); 
    } catch (OutOfMemoryError e) {         
        e.printStackTrace();
    }
}
30
NagarjunaReddy

多分これはあなたを助ける?

マニフェストを追加

Android> v3

<application
    ....
       Android:largeHeap="true"> 
42
SKULL

一般的な修正:

1.コンテキストを修正します。

適切なコンテキストを使用してみてください。たとえば、Toastは1つではなく多くのアクティビティで見ることができるので、トーストにはgetApplicationContext()を使用します。 :

Intent myService = new Intent(getApplicationContext(), MyService.class)

このコンテキストを適切なコンテキストのクイックガイドとして使用します。 enter image description here

オリジナル コンテキストに関する記事はこちら

2.実際にサービスを終了していることを確認します。

たとえば、Google Location Service APIを使用するintentServiceがあります。そして、googleApiClient.disconnect();を呼び出すのを忘れました:

_//Disconnect from API onDestroy()
    if (googleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, GoogleLocationService.this);
        googleApiClient.disconnect();
    }
_

3.画像とビットマップの使用状況を確認します。

正方形のライブラリPicassoを使用している場合、.fit()を使用しないことでメモリリークが発生していることがわかりました。平均で50MBから19MB未満:

_Picasso.with(ActivityExample.this)                   //Activity context
                .load(object.getImageUrl())           
                .fit()                                //This avoided the OutOfMemoryError
                .centerCrop()                         //makes image to not stretch
                .into(imageView);
_

4.ブロードキャストレシーバーを使用している場合は、登録を解除します。

5. _Java.util.Observer_(オブザーバーパターン)を使用している場合:

必ずdeleteObserver(observer);を使用してください

34
CommonSenseCode

これを回避するには、次のようにします。

Drawable drawable = resultMatchHeaderContainer.getDrawable();

if (drawable instanceof BitmapDrawable) {
    BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
    if (bitmapDrawable != null) {
        Bitmap bitmap = bitmapDrawable.getBitmap();

        if (bitmap != null && !bitmap.isRecycled())
           bitmap.recycle();
    }
}

Imageviewでのビットマップの読み込みは常にメモリ不足の問題の原因であり、非常に一般的であるため、imageviewとビットマップを非常に慎重に処理する必要があります。あなたができることは、画像ビューに背景ビットマップを設定している間に、まずドロアブルを取得してリサイクルし、メモリから削除してから新しいビットマップを設定します。これにより、OOMの問題を回避できます。さらに。 BitmapFactoryOptionsを使用して、ビットマップのサイズを縮小できます。のような:

// decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
    try {
        // decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        FileInputStream stream1 = new FileInputStream(f);
        BitmapFactory.decodeStream(stream1, null, o);
        stream1.close();

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_WIDTH
                    || height_tmp / 2 < REQUIRED_HIGHT)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        // decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        FileInputStream stream2 = new FileInputStream(f);
        Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
        stream2.close();
        return bitmap;
    } catch (FileNotFoundException e) {
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
8
Avtar Guleria

画像をメモリにロードする前に、画像を圧縮します

Bitmap original = BitmapFactory.decodeStream(getAssets().open("1024x768.jpg"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
original.compress(Bitmap.CompressFormat.PNG, 100, out);
Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));

Log.e("Original   dimensions", original.getWidth()+" "+original.getHeight());
Log.e("Compressed dimensions", decoded.getWidth()+" "+decoded.getHeight());  

リソースからビットマップを取得する場合、その場合、ビットマップのサイズは電話の画面密度に依存します

Bitmap bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.img_1024x768)).getBitmap();
Log.e("Dimensions", bitmap.getWidth()+" "+bitmap.getHeight());
1
rajahsekar

これはいくつかの理由で発生する可能性があります。コードの他の部分への参照が長すぎます。 多くの参照を保持するとともにOOMなどを提供する大きなビットマップにロードする可能性があります.

通常、OOMが発生すると、hprof(ヒープのスナップショット)がsdcard(またはsdcardが存在しない場合は内部ストレージ)のルートに作成され、Eclipse MAT(Eclipseを使用する場合はAndroidツールに含まれます)。最初にhprof-convツールでhprofを変換する必要があるかもしれません。 Eclipse MATの使用方法のチュートリアルを1つ示します。 RAM使用状況の調査リークの疑いのあるレポートは、hprofがEclipse MATにロードされたときに最初に読むのに適しています

プロファイリング後、 ビットマップを効率的に表示する から画像を効果的にロードする方法を読むことができます。

niversal image loaderpicasso などの人気のある画像読み込みライブラリもいくつかあり、必要なことを簡単に実行できます。

1
Magnus

最終ビットマップ笑顔= BitmapFactory.decodeResource(getResources()、R.drawable.Emo_im_happy);

コール

String pathname=BitMapToString(smile);

そして、呼び出します

_setImagesNew(linearview,pathname,activity);
_

...

_public String BitMapToString(Bitmap bitmap) { 
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
             bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); 
        byte[] b = baos.toByteArray();
      String temp = Base64.encodeToString(b, Base64.DEFAULT);
      return temp;
 }


 public static void setImagesNew(LinearLayout linearLayout, String pathName,
                Activity activity) {

            Bitmap bmp = decodeSampledBitmapFromResource(pathName,
                    getDeviceWidth(activity), getDeviceHeight(activity));

linearLayout.setBackgroundDrawable(bmp);


            bmp = null;
            System.gc();
            Runtime.getRuntime().gc();

        }
    public static Bitmap decodeSampledBitmapFromResource(String pathName,
            int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pathName, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(pathName, options);
    }

    public static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and
            // keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

    @SuppressLint("NewApi")
    public static int getDeviceWidth(Activity activity) {
        int deviceWidth = 0;

        Point size = new Point();
        WindowManager windowManager = activity.getWindowManager();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            windowManager.getDefaultDisplay().getSize(size);
            deviceWidth = size.x;
        } else {
            Display display = windowManager.getDefaultDisplay();
            deviceWidth = display.getWidth();
        }
        return deviceWidth;
    }

    @SuppressLint("NewApi")
    public static int getDeviceHeight(Activity activity) {
        int deviceHeight = 0;

        Point size = new Point();
        WindowManager windowManager = activity.getWindowManager();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            windowManager.getDefaultDisplay().getSize(size);
            deviceHeight = size.y;
        } else {
            Display display = windowManager.getDefaultDisplay();
            deviceHeight = display.getHeight();
        }
        return deviceHeight;
    }
_

すべての関数をアクティビティに入れて、setImageNew()のみを呼び出し、imageview、sdcardpathnameおよびactivityでパラメータを渡してください

このコードを実装した後、クラッシュしないことを願っています。私はあなたと同じ問題を起こすからです。

1
dipali

これは、ビットマップリソースが正しく破棄されない場合に発生する可能性があります。メモリに適合するかどうかを確認するために、寸法を読むことをお勧めします。 http://developer.Android.com/training/displaying-bitmaps/load-bitmap.html

0
Selvan