How to track down memory leak - Find living references - android

I have a fairly complex app -
The UI Activity launches a Service and sets up 2 way AIDL callbacks so the two can communicate.
The service runs forever (unless hits 'off' button in UI Activity).
The problem is when the user exits the Activity, the Activity memory is not released.
-The amount of memory used by my app is the same even if the UI Activity has been closed.
-The heap still shows mapTiles and other UI crap on it even if the UI Activity has been closed.
So my guess is somehow the Service is holding references to the Activity. I know the many articles warning about leaking the Activity Context. The Service only references the Activity through a Weak Reference stored at Application scope. (a class that extends Application)
Is there any way to find what specifically is referencing the Activity? The dominator tree shows mapTiles and ListView layouts eating all my memory... but I can't find the reference to the Activity which is keeping that stuff alive.
Also, is there a way to dump an HPROF heap dump thing if OutOfMemoryException occurs?

The problem is when the user exits the
Activity, the Activity memory is not
released.
There is no "exit Activity" in Android. Calling finish() or pressing back on the activity does not remove objects from memory that the activity used. Android inherently takes care of this itself at some random point in the future.
If you want your objects to be released from memory at the moment the activity finishes, you need to manually release them yourself.
Edit: The class that can be used to find memory usage is the ActivityManager.

If it's not yourself who is holding a reference ("references the Activity through a Weak Reference stored at Application scope", do you null it? I wonder why you reference the activity in the service, usually its the other way), did you try to execute a GC? As long as there is enough memory left, no gc will take place to move the trash away.

Related

Android application lifecycle clarification

Can anybody confirm the following regarding the android application lifecycle?
1) When application is in foreground the memory will contain instance of the Application object, instances of all activities (not killed) and all the object references that are referenced from one of the root's (haven't been garbage collected)
2) When application goes to background, at some point the Android Framework can:
a) Kill the whole process given to the purpose of the application which will essentialy erase all the objects from the memory
b) Kill ONLY (so essentialy no other object reference will be deleted) the activities (by finishing them and in essence any fragments as well) saving their states and creating the Activities Stack and leaving anything else (Application object, any other static objects, references that are reachable from any of the roots).
I'm mostly interested in 2b, but I would appriciate confirmation on all of these points as I'm trying to grasp mentaly the whole concept from start to finish.
If you are looking for official confirmation then better ask Google only :).
but i feel after reading this you will get a better understanding of these concept.
Android memory management
android process lifecycle
Answer for 1st question:
yes confirm using DDMS.
answer for 2a question: yes OS can kill process any point of time when needed memory for other process which will result into killing all object related to process.
answer for 2b questiong:
From official documentation
Process Lifecycle 3. A background activity (an activity that is not visible to the user and has been paused) is no longer critical, so the system may safely kill its process to reclaim memory for other foreground or visible processes. If its process needs to be killed, when the user navigates back to the activity (making it visible on the screen again), its onCreate(Bundle) method will be called with the savedInstanceState it had previously supplied in onSaveInstanceState(Bundle) so that it can restart itself in the same state as the user last left it.
Yes you are mostly correct about 2b).
If an activity is paused or stopped, the system can drop the activity
from memory by either asking it to finish, or simply killing its
process.
However there are instances where onSaveInstantSate isn't called:
Note that it is important to save persistent data in onPause() instead
of onSaveInstanceState(Bundle) because the latter is not part of the
lifecycle callbacks, so will not be called in every situation as
described in its documentation.
Android Docs Source
You can request android to always destroy activities on background by enabling the following developer option. If you are debugging your app you should be able to step through the life cycle methods and see what is happening.
Settings -> Developer options -> Apps -> Don't keep activities
There is no typical life-cycle for application exists. Application object lives in memory until it is not being killed either by Android itself or by manually by user.
For the above points, here are your answers:
1) This is true.
2) a) That is also true.
2) b) When application goes background, you can only save the data of the current activity that was in foreground. Also, when you kill the application it self (by removing it from recent list), all the activities in the app stack and their saved data (not persistent data) got killed as application is the base for all the activities.
1) When application is in foreground the memory will contain instance
of the Application object, instances of all activities (not killed)
and all the object references that are referenced from one of the
root's (haven't been garbage collected)
> There will only ever be a few such processes in the system, and these
> will only be killed as a last resort if memory is so low that not even
> these processes can continue to run. Generally, at this point, the
> device has reached a memory paging state, so this action is required
> in order to keep the user interface responsive.
2) When application goes to background, at some point the Android
Framework can:
.
a) Kill the whole process given to the purpose of the application
which will essentialy erase all the objects from the memory
> These processes have no direct impact on the user experience. Provided
> they implement their Activity life-cycle correctly (see Activity for
> more details), the system can kill such processes at any time to
> reclaim memory for one of the three previous processes types. Usually
> there are many of these processes running, so they are kept in an LRU
> list to ensure the process that was most recently seen by the user is
> the last to be killed when running low on memory.
b) Kill ONLY (so essentialy no other object reference will be deleted)
the activities (by finishing them and in essence any fragments as
well) saving their states and creating the Activities Stack and
leaving anything else (Application object, any other static objects,
references that are reachable from any of the roots).
Partially as in point 2.a.'s explanation
> Usually there are many of these processes running, so they are kept in an LRU
> list to ensure the process that was most recently seen by the user is
> the last to be killed when running low on memory.
Source - developer.android.com
Well this thing depends upon how Android OS operates. Android Device is an embedded System but works almost same as a PC and when I say Android as an OS, it will definetely have all the features of an OS. The thing which you are pointing upon is the Memory Management and Scheduling feature of Android OS.
MMU(Memory Management Unit) logically give preference to currently executing task i.e ur launcher or any other Application which u r working upon. Two things I want to answer which can help u bit more:
Views (whether xml generated or Javacode generated, they are dynamically generated.).
Android OS runs all apps as a process with sub processes(Activities) on a Dalvik Virtual Machine.
All your Activities before they are created they are null, when they are created then their instance is generated. Upon opening them again their saved instance is again viewd(Concept of Singleton Design Pattern).
So let me tell you that I don't think that both of the options are right. What I beleive is following:
1. View will always be generated dynamically.
2. Instance will be saved in Memory.
3. On background going of Application the whole process with instances available will be their in Memory.
Ok, during my search quest in recent weeks I was able to get some more information and now I can answer my own (and hopefully for others) questions:
1) Correct
2a) Correct
2b) False. The android framework, if in need of memory or if due to some other reason it has to "kill/reduce" the application it can do so only by killing the whole process that is dedicated to that application. The android framework can neighter kill chosen activity(ies) or kill all activities but leave all other objects alive (like Application object, singletons etc.)

Is there an afterlife for Activity?

Let's say we have a reference (strong reference) to an activity object.
What happens to Activity object after it was:
finished or
changed orientation or
put on pause or stopped because of switch to another activity
I am talking about a case when application wasn't killed by OS but when a user continue to use the application.
Will activity ever be released, if we continue to keep this strong reference?
One one hand, as I understand, if somebody keeps a reference to an object it can't be released/deallocated. On other hand, Android is quite aggressive with releasing unused activity and I wonder whether Dalvik machine has some exception which will allow to release/deallocate an activity which is referenced.
These article doesn't talk directly about a case, when somebody is keeping a reference:
http://developer.android.com/training/basics/activity-lifecycle/starting.html#Destroy
http://developer.android.com/reference/android/app/Activity.html
There is only one hint which I got:
There is a method Activity.isDestroyed() which kind of implies that object won't go away immediately.

Android - Efficient way to pass event notifications to activity that may not be active?

I have a complex app that has background threads (that could be in a service) which, when they receive data from the internet, need to notify my main display activity (to update on of several status indicators). All run in the same process (I see no reason to do otherwise).
However, in some circumstances, these events are frequent - 5 per second. Also, the events may occur when the activity is not-visible or even destroyed. I think the only thing novel about this question is the issue of efficiency. I still target the G1, for example.
There are a number of methods mentioned in this thread, but I don't know which of these are efficient enough, and will work if the activity is destroyed. Those methods are the "Android way" which I would prefer to follow.
I have three ugly anti-Android ways that work, but they also have drawbacks:
Have a thread in the activity that is waits on a semaphore, and when released, does the update. Disadvantages: extra thread, how to handle several event types
Like #1, but use a concurrent blocking queue object. Disadvantages: extra thread, same type of event may end up in the queue multiple times (not good)
Keep a static reference to a handler on the activity, and use that to run an updater. Disadvantages: (a) may leak a reference to the activity? (b) what happens when the activity changes state? (c) multiple runnables could end up there when only one is needed.
Also, the events may occur when the activity is not-visible or even destroyed.
If your activity is destroyed, there is nothing to update. If and when the user elects to re-visit that activity, the activity can get the current information in onResume() for display.
If your activity is in the background, there is nothing that needs to be updated, either. Again, if and when the user elects to re-visit that activity, the activity can get the current information in onResume() for display.
The ONLY time you need an activity to be notified of events in real time is if that activity is in the foreground. In that case, any of the solutions I outlined in the answer you linked to could work. The binding option or Messenger are probably the lightest-weight solutions.
I have a complex app that has background threads (that could be in a service)
Not "could be" -- "must be", if they are to live beyond the scope of any given activity instance.
I have three ugly anti-Android ways that work
None of those work without potential memory leaks.

Android Activity Garbage Collection

I noticed this behavior while developing a simple Android game which has 2 activities.
The game has 2 activities, the first is a screen which allows the user to select the opponent type, level etc. and the second the actual game screen.
The second activity creates an object of a GameManager class which handles all the game processing.
This GameManager class also creates a CountDownTimer which it starts to prompt user input (on timeout the game is defaulted to the opponent).
I've noticed that if the user exits the second activity (returns to the first) and then launches a new game again, the previous timer is still running until completion.
I've handled this by explicitly cancelling the timer (from the onDestroy() of the second activity) as just setting the timerobject to 'null' did not cancel the timer.
However I'm curious as to why the previous timer was running even after my activity was exited the first time? Shouldn't the GC have deleted all the objects instantiated by the second Activity (and whatever child objects it created) when it was exited? Would be great to know the reason behind the observed behavior?
TIA
Shouldn't the GC have deleted all the objects instantiated by the second Activity (and whatever child objects it created) when it was exited?
This isn't how Garbage Collection works. The GC isn't responsible for 'deleting objects' - it's responsible for picking up 'orphaned' objects and freeing their resources. Even then, a GC isn't guaranteed to get to all of the orphans in a timely manner.
Further to that, any objects which may be 'system' objects and need to be released explicitly may never be released if your code doesn't do it. Other issues with GC may include creating objects which other threads (other than the Activity which created them) may have a reference to.
You mention your 'timer' but don't explain what sort of class you are using for it. I suggest read up specifically about that class and see what the implications are for ceation/deletion (possibly explicit 'release' of resources).
GC is a very grey area on any platform. With Android it's normally pretty immediate but with the nature of the Activity life-cycle it's very difficult to predict what will happen.
In general make use of onCreate, onPause and onResume within Activities and also things like savedInstanceState and SharedPreferences to keep track of what is going on.
CountDownTimer is not bound to an activity as you already found out. A hint to lookout for in these cases is that a class does not receive any Context in its constructor. Hence it can't be bound to an activity.

How long does my subclass of Android's 'Application' class stick around for?

In my application, I use a subclass of the Application object to store some references to complex objects I need to access from all of my activities. When my app starts, the startup activity checks one of these references, in this case a Location, and if it is null, it starts the LocationListeners which populate the reference for further use.
If I back out of the app to the launcher screen, and re-launch it, the Application object still has the reference from the previous use a few moments prior. This is fine, and is what I'd expect, but I'm curious how long the Application object is kept around once I've back'ed out of my application? (onDestroy() has been called on all activities, nothing in the stack.)
When is it finally killed? I know it does finally get killed as when I've not used the app in a while, it will search for location on startup (indicating the aforementioned null reference.)
(Also, is storing refs there like that a good idea?)
Thanks in advance gang! :-)
It stays around as long as the application is in memory. It only finally goes away when either someone forcible terminates your application (either using a task killer or from the application settings) or when Android decides it wants to reclaim the memory that your app is using (and this typically only happens when your app has been closed for a while and the phone is running low on memory).

Categories

Resources