0

In my android application the onDestroy method on the Activity is never called before the application runs out of memory. I can call finish() on the onStop() method of the activity and will never run out of memory, however then I lose the back button functionality.

Sorry I can't be any more specific about the issue. Everything I have read is that android is supposed to call the onDestroy() and finish() when resources get low however this is never called.

I would like the activities at the bottom of the stack to have finish() called on them. They aren't and I eventually run out of memory.

I call: adb shell dumpsys meminfo com.mypackage

And I see the activity count always incrementing until the OutOfMemoryError. If I call finish() on the activities at onStop() then the activity count will stay around 30 and no OOME.

Thanks for any advice. Memory management on android is a disaster, thanks for tips you have.

  • I don't know where you read that, I haven't. Identify how you're filling up the memories and fix that. http://www.raizlabs.com/dev/2014/04/hunting-your-leaks-memory-management-in-android-part-2-of-2/ https://developer.android.com/training/articles/memory.html – zapl Nov 15 '14 at 02:55
  • The issue is that the onDestroy is never called, ever. The entire activity context and its views is prevented from GC and any class variables in the activity are pinned. This leaks a ton of memory and there's no way to collect it. All I can think of is to register the new activity in the Application and maintain a stack of the activities via weak references so I can manually call finish() on activities at the bottom of the stack. – Blair Cruz Nov 15 '14 at 03:51
  • Dianne Hackborn says you should use fragments: http://stackoverflow.com/a/7576275/995891 – zapl Nov 15 '14 at 04:05
  • Typically, if onDestroy() is not called it is because the process is being killed, so normal allocations will be freed by the process death anyway. – Chris Stratton Nov 15 '14 at 06:02

1 Answers1

1

Everything I have read is that android is supposed to call the onDestroy() and finish() when resources get low however this is never called.

There is no guarantee that onDestroy() will ever get called by the system... the operating system has the ability to kill any process it pleases without warning at any time it wants. This was an intentional design decision, as it ensures the system remains in complete control of the device even in the presence of malicious applications.

Memory management on android is a disaster.

The system is very good at destroying background activities to make room for others when memory becomes low. You shouldn't have to worry about how many activities are currently in the back stack and you certainly shouldn't be holding weak references to these activities just so you can manually call finish() on them at a later time. The system will do all of this for you.

If you are getting an OutOfMemoryError then that means either your application has a severe memory leak that you need to fix, or your application is allocating huge chunks of memory at a time until the runtime can no longer take it.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • Thanks for the response, this has been frustrating issue. How am I supposed to call the finish() myself? All I can think of is to maintain a static Stack of the activities myself (via WeakReference) and manually call finish on ones at the bottom that are unlikely to be reached via back button. – Blair Cruz Nov 15 '14 at 03:59
  • Also, all the views will stay alive while the Activity context is open and leak as well. If I call the adb dumpsys I see: Objects Views: 5381 ViewRootImpl: 45 AppContexts: 48 Activities: 45 and the number of views will grow without bounds – Blair Cruz Nov 15 '14 at 04:01
  • 1
    I just updated my answer a second ago (I'm guessing you started typing up your comment before you saw the updated version). Like I said, the system will destroy activities whenever memory becomes low. You shouldn't have to worry about this. You should delete any static lists of activities you are currently maintaining as well as any logic where you are manually calling `finish()` on your background activities as doing so is neither necessary nor recommended. – Alex Lockwood Nov 15 '14 at 04:01
  • Ironically, holding a static list of activity references is much more likely to cause memory leaks than prevent them (since doing so prevents the runtime from garbage collecting the activity objects and all of the resources/views associated with them... even after the system has destroyed the activity). – Alex Lockwood Nov 15 '14 at 04:07
  • It seems that in fact it doesn't clean activities on the backstack, http://commonsware.com/blog/2011/10/03/activities-not-destroyed-to-free-heap-space.html - also above link which came from here, fragments can solve that since they get `onDestroyView`d – zapl Nov 15 '14 at 04:08
  • @BlairCruz Also, how many activities does your application have? I assume your backstack isn't actually 45 activities long...? Perhaps you are leaking activity context's somewhere without realizing it. – Alex Lockwood Nov 15 '14 at 04:12
  • @AlexLockwood I would certainly hold the static list of the activities via weak reference so they can still be collected, and still allow referencing. – Blair Cruz Nov 15 '14 at 04:36
  • 1
    @BlairCruz You still shouldn't do that. Like I said, there is absolutely no reason why you would ever need to do that. If `adb dumpsys` is reporting 45 activities are in memory, then you are likely leaking an activity context at some point... once you get rid of that memory leak, hopefully you'll be able to avoid the out of memory error. – Alex Lockwood Nov 15 '14 at 04:39
  • @AlexLockwood The backstack is generated as new activities are started, there are 6 or 7 different types of activities, and I switch between them via intent = new Intent(context, SomeActivity.class); context.startActivity(intent); – Blair Cruz Nov 15 '14 at 04:42
  • @AlexLockwood the activity(context) is not pinned anywhere. When you launch a new Activity would a new Activity not be created? – Blair Cruz Nov 15 '14 at 04:44
  • @BlairCruz Maybe you should use DDMS to obtain a more detailed look at how much memory your application is using. There is a good article on how to use DDMS's memory profiling tools [**here**](http://developer.android.com/tools/debugging/ddms.html#heap). – Alex Lockwood Nov 15 '14 at 04:47
  • @zapl thanks for the link, what I suspected, android never cleans up activities. I will look at using some of those intent flags or fragments in the application. The android "memory model" completely breaks encapsulation, what a mess. – Blair Cruz Nov 15 '14 at 04:47
  • It should be easy to see if there is a leak or really a gigantic backstack: if an activity stays in memory after `onDestroy` (and garbage collection) you have a leak, otherwise android references it because it considers it still valid. – zapl Nov 15 '14 at 04:49
  • @BlairCruz "The android memory model completely breaks encapsulation"... no it doesn't. Android's memory model was designed by extremely intelligent engineers based on the idea that (1) any number of applications can be running on the device at once, (2) switching between foreground/background applications should be _fast_, and (3) phones have limited memory and no swap space. If you are getting an out of memory error, then that is a bug in your application, not the framework. – Alex Lockwood Nov 15 '14 at 04:59
  • You can refer to these articles for more information: (1) [Multitasking the Android Way](http://android-developers.blogspot.com/2010/04/multitasking-android-way.html), (2) [Managing Your Application's Memory](https://developer.android.com/training/articles/memory.html), (3) [Using DDMS](http://developer.android.com/tools/debugging/ddms.html), (4) [Android Studio Memory Monitor](http://tools.android.com/recent/androidstudio0810released). – Alex Lockwood Nov 15 '14 at 05:00
  • @AlexLockwood The point here is, Android isn't smart enough to manage your backstack *unless* your app is in the background and *another* app needs the memory. That breaks the idea that you don't have to care about memory as long as you don't leak Activity contexts. You are responsible for the OOM error, not because of context leaks, because you're using the backstack wrong. – zapl Nov 15 '14 at 10:58