I have an activity that looks like the following:
class MyActivity extends Activity {
Runnable refreshTimer = new Runnable() {
public void run() {
refresh();
}
};
protected onCreate(...) {
handler.postAtTime(refreshTimer, ...);
}
protected onDestroy() {
handler.removeCallbacks(refreshTimer);
}
protected void refresh() { ... }
}
After onDestroy is called, there are still messages in the activity's MessageQueue that contain references to MyActivity$0 (the refresh Runnable) for some reason. Because MyActivity$0 has an implicit reference to MyActivity, this causes a memory leak of the MyActivity context.
The result of merge_shortest_paths for android.app.Activity excluding phantom,soft,weak,etc references using Eclipse Memory Analyzer Tool:
(The source code above is a simplification of the actual object relationship displayed in the MAT dump)
Shouldn't calling removeCallbacks remove any references to the runnable objects from the Queue? Why am I leaking contexts?
The Memory Profiler is a component in the Android Profiler that helps you identify memory leaks and memory churn that can lead to stutter, freezes, and even app crashes. It shows a realtime graph of your app's memory use and lets you capture a heap dump, force garbage collections, and track memory allocations.
A memory leak happens when memory is allocated but never freed. This means the GC is not able to take out the trash once we are done with the takeout. Android has a 16ms drawing window, and the GC normally takes less time to deal with memory.
Memory leak occurs when programmers create a memory in heap and forget to delete it. The consequences of memory leak is that it reduces the performance of the computer by reducing the amount of available memory.
Memory leaks are a class of bugs where the application fails to release memory when no longer needed. Over time, memory leaks affect the performance of both the particular application as well as the operating system. A large leak might result in unacceptable response times due to excessive paging.
Something to try:
According to the android docs:
OnDestroy: The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
When you are exiting your activity, it looks like there are still a bunch of queued up messages and the context for unregistering is not invoking the cancel callback.
What you should do is unregister your runnable in onPause: This callback is mostly used for saving any persistent state the activity is editing, to present a "edit in place" model to the user and making sure nothing is lost if there are not enough resources to start the new activity without first killing this one. This is also a good place to do things like stop animations and other things that consume a noticeable amount of CPU in order to make the switch to the next activity as fast as possible, or to close resources that are exclusive access such as the camera.
Typically a Receiver or "Scheduled" Runnable will register in onResume, and unregister in onPause for better lifecycle pairing
Without seeing what you are doing in refresh, it is tough to tell, it could be leaking due to activity references that are activity scoped referenced in the refresh method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With