31

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 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.access600ドル(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

This is the line where it is happening:

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();
 }
}
xarlymg89
2,6072 gold badges30 silver badges43 bronze badges
asked Jan 9, 2014 at 5:08
6
  • 1
    You are trying to load a bitmap into an ImageView. Clearly the bitmap you are sometimes loading is too large to fit in memory. You need to scale down the image as you read it. Look at inSampleSize Commented Jan 9, 2014 at 5:12
  • @NagarjunaReddy have you solved your problem or not? Commented Jan 9, 2014 at 5:28
  • no not yet trying...@dipali Commented Jan 9, 2014 at 5:30
  • what?do you not solved your prblm? Commented Jan 9, 2014 at 5:34
  • that error occur only some time not all times @dipali Commented Jan 9, 2014 at 5:43

8 Answers 8

44

maybe this help you ?

add manifest

android> v3

<application
 ....
 android:largeHeap="true"> 
answered Jun 3, 2014 at 6:29
Sign up to request clarification or add additional context in comments.

2 Comments

The use of largeHeap is not recommended in all cases, please use it very cautiously, it might slow other running application, and also impact your app's reactiveness, since the garbage collector with be solicited more often. For more information check this speech from google i/o youtube.com/watch?v=_CruQY55HOk
Never request a large heap simply because you've run out of memory and you need a quick fix—you should use it only when you know exactly where all your memory is being allocated and why it must be retained. Yet, even when you're confident your app can justify the large heap, you should avoid requesting it to whatever extent possible. see developer.android.com/training/articles/memory.html
37

Common fixes:

1. Fix your contexts:

Try using the appropiate context: For example since a Toast can be seen in many activities instead of in just one, use getApplicationContext() for toasts, and since services can keep running even though an activity has ended start a service with:

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

Use this table as a quick guide for what context is appropiate: enter image description here

Original article on context here.

2. Check that you're actually finishing your services.

For example I have an intentService that use google location service api. And I forgot to call googleApiClient.disconnect();:

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

3. Check image and bitmaps usage:

If you are using square's library Picasso I found I was leaking memory by not using the .fit(), that drastically reduced my memory footprint from 50MB in average to less than 19MB:

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

4. If you are using broadcast receivers unregister them.

5. If you are using java.util.Observer (Observer pattern):

Make sure to to use deleteObserver(observer);

answered Feb 10, 2016 at 23:13

Comments

9

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;
}
Bhavinkumar Patel
5151 gold badge13 silver badges28 bronze badges
answered Jan 9, 2014 at 5:17

6 Comments

Why it is downvoted, let me know also the reason for that..Whosover downvoted it please mentioned the reason for it..
Although this is a nice idea in theory, it doesn't work so well in practice. The call to Recycle() is merely a hint to the GC to reclaim memory. It may not be reclaimed by the time you create your new image and as such may still cause your application to crash. More to the point though, the GC will automatically reclaim the memory when over the next few CG cycles.
Really why somebody downvoted ,he/she is real nerd ..Most of the time it works ..It worked for me ..in my project..
i was about to answer the same so +1
Thanks. Shakeeb Ayaz. @TheIT, Do you mean that recycle method on bitmap is not useful or what if that then in Which situation we should use it?
|
1

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());
answered Jan 9, 2014 at 5:15

1 Comment

For your second point, I would look at loading the bitmap at a reduced scale if possible using BitmapFactory.Options and the BitmapFactory.decodeResource() method. See developer.android.com/training/displaying-bitmaps/… for more details.
1

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.

answered Jan 9, 2014 at 8:22

1 Comment

@NagarjunaReddy updated this answer with some more ideas what you could do. I would start off by analyzing the hprof to see if you're holding on to too many refs of some kind, if that's not the case you could consider using some image libraries which are caching images and adapting them to your needed view sizes needs with ease.
1

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..

USER9561
1,0843 gold badges16 silver badges42 bronze badges
answered Jan 9, 2014 at 6:01

4 Comments

final Bitmap smile = BitmapFactory.decodeResource(getResources(), R.drawable.emo_im_happy);
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; }
call BitMapToString(smile);
0

This may happen if the bitmap resource is not disposed correctly. It is better to read the dimensions to see if it fits the memory. http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

answered Jul 19, 2015 at 19:03

Comments

0

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

answered Aug 4, 2020 at 15:36

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.