2

I have a program that loads a bitmap from gallery (by dispatching intent for result) and then displays the image. Then when leaving the activity that displays the image, I call bm.recycle(). But that does not seem to be recycling the bitmap? I know this because of the problem described in the post here: android bitmap out-of-memory error after getting same image twice in a row.

This question is specifically as stated in the present title: Why is onDestroy not recycling the bitmap? (I only provide the link for some context not as a distraction)

Here is my onDestroy:

@Override protected void onDestroy() { super.onDestroy(); unbindDrawables(findViewById(android.R.id.content).getRootView()); System.gc(); myImage.recycle(); myImage = null; } 
3
  • Maybe you recycle only last bitmap you have created. You should recycle bitmap when you are done with it. Commented Apr 26, 2013 at 19:40
  • By done with it do you mean right after displaying it in a view as either setImageBitmap or setDrawable? Commented Apr 26, 2013 at 19:43
  • Not exactly if you done it, you may get exception. I wanted to say that do not wait until your activity to enter onDestroy(), if a bitmap is not useful for you anymore, you can recycle it. Commented Apr 26, 2013 at 19:51

2 Answers 2

3

You have probably somewhere a reference which you forgot to free. See also this answer about How to find Memory Leak Class/Activity in Android. I'm sure it will help you to find fast where you leak your memory.

Also remember that you have to free the memory by yourself. The callback onDestroy() does not do that for you.


First you need to install the MAT plugin. After a restart click on Dump HPROF file:

Device controls

After some time about 30 seconds. You'll get a dialog where you can click on finish. Than you get this view:

Dump result

There you left click on the biggest part and filter for with outgoing references. Then you get this view here:

Here you can see that I missed to delete items in my ContentManager where several items were stored in my pending HashMap.

Sign up to request clarification or add additional context in comments.

Comments

2

Look at the Android Activity Lifecycle which shows which methods should be used to create and release resources. It shows that the corresponding function to onCreate() is not necessarily onDestroy() because the developer has no idea when the Android OS will call onDestroy().

The Answer:

Therefore, in your particular instance, you could free or recycle() your Bitmap in onStop(), not in onDestroy().

onPause()/onResume():

Additionally, it is better practice to free resources in onPause() and then recreate them in the corresponding method onResume().

inSampleSize and OutOfMemoryError:

You should also make sure to open your Bitmap images as small as possible with BitmapFactory.Options.inSampleSize in order to reduce the possibility of receiving an OutOfMemoryError. There are many examples on this site demonstrating the use of inSampleSize. Here is just one of them: Resize picture into according to textivew's size

Android Activity Lifecycle:

Android Activity Lifecycle

5 Comments

ah, I have been reading some blogs that pair onCreate/onDestroy
Incorrect. The opposite of onCreate() is indeed onDestroy() - these methods concern lifetime. The opposite of onStart() is onStop(), a pair of methods which concern (at least partial) screen visibility. Your confusion appears to come from the atypical path of the app being killed without onDestroy() ever being called.
In the case where onDestroy() is not called, it is because the process has been killed, at which point there's neither need - or opportunity - for developer-written code to free any resources. Remote resources in other processes linked to those in the dead process should be freed if Binder IPC has been properly used to notify of remote object death. Similarly, OS level resources should be getting freed by process death itself.
When I change onDestroy to onPause, I get a nullPointerException at unbindDrawables(findViewById(android.R.id.content).getRootView()). The exception says E/AndroidRuntime(3430): java.lang.RuntimeException: Unable to pause activity ... I am guessing it's referring to getRootView.
Are you calling onPause() [bad]? Does onPause() now call super.onPause() [good] or super.onDestroy() [bad]? Also, once you recycle() a Bitmap, you must be sure not to use it again unless you recreate it. Use isRecycled() to determine if you are trying to access a Bitmap that has been recycled.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.