Android OutOfMemoryError:?

前端 未结 8 1493
孤街浪徒
孤街浪徒 2020-11-28 06:02

I am sporadically getting an OutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB) in one of my apps. What can I do to diagnose this?

  01-09         


        
相关标签:
8条回答
  • 2020-11-28 06:41

    maybe this help you ?

    add manifest

    android > v3

    <application
        ....
           android:largeHeap="true"> 
    
    0 讨论(0)
  • 2020-11-28 06:42

    You can do following to avoid this.

    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();
        }
    }
    

    Loading Bitmap in Imageview always been a cause of out of memory issue it is very common so we have to handle imageview and bitmaps very carefully. What you can do is While setting any background bitmap to your imageview first get the drawable and recycle it so that it is removed from memory and then set the new bitmap. This will help to avoid any OOM issue. Further. You can use BitmapFactoryOptions to reduce the size of your bitmap. like:

    // 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;
    }
    
    0 讨论(0)
  • 2020-11-28 06:48

    I solved the same problem by:

    • reduce image dimension from 5000x2500 to 320x240 - 1080x720 (few drawabls folders)
    • converting the PNG image to WEBP format. Its size has decreased 50 times (from 1.2 MB to 30 KB).

    https://developer.android.com/studio/write/convert-webp#convert_images_to_webp

    0 讨论(0)
  • 2020-11-28 06:51

    final Bitmap smile = BitmapFactory.decodeResource(getResources(), R.drawable.emo_im_happy);

    Call

    String pathname=BitMapToString(smile);

    and then call

    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;
        }
    

    please put all function in your activity and call only setImageNew() and pass parameter in imageview ,sdcardpathname and activity

    I hope it will not crash after you implement this code. because I arise same problem as you..

    0 讨论(0)
  • 2020-11-28 06:52

    Before loading images into memory compress your images using

    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());  
    

    If you are geting your bitmap from a resource, in which case the bitmap dimension will depend on the phone screen density

    Bitmap bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.img_1024x768)).getBitmap();
    Log.e("Dimensions", bitmap.getWidth()+" "+bitmap.getHeight());
    
    0 讨论(0)
  • 2020-11-28 06:55

    This could occur for several reasons, you might be keeping references to other parts of your code too long. You might be loading to large bitmaps which together with holding on to many references gives you OOM, etc.

    Normally when an OOM occurs a hprof (snapshot of the Heap) is created on the root of the sdcard (or internal storage if sdcard does not exist), which can be read by tools like Eclipse MAT (included in the android tools if you use Eclipse). First one might need to convert the hprof with hprof-conv tool. Here's one tutorial of how to use Eclipse MAT: Investigating Your RAM Usage. The leak suspects report is a good first read when hprof is loaded in Eclipse MAT

    After profiling you you could read up on how to load images effectively from Displaying Bitmaps Efficiently

    There's also several popular image loading libraries such as universal image loader and picasso available, that do what you need with ease.

    0 讨论(0)
提交回复
热议问题