To clear all background activities I did the following:
I kept a static array list, and whenever I used to go from one activity to another, in the onCreate() method of new activity, I added the object of current activity into that list like this:
SomeClass.addActivity(CurrentActivity.this);
I added the above statement in each activity.
The addActivity():
public void addActivity(final Activity activity) {
activityList.add(activity);
}
And when I wanted to clear the stack, I called:
public boolean clearStack() {
for (Activity activity : activityList) {
activity.finish();
}
activityList.clear();
return (activityList.isEmpty());
}
In this way, I cleared my activity stack.
But it produced a memory leak. It's not the right way to do that. It's not ok to hold references to activities. Can you guys explain me why and how exactly memory leak occurred in this case?
I used MAT for eclipse to find this memory leak in my app.
Any help would greatly be appreciated.
Holding references to activities outside their context (when they are in background or "closed"/finished) causes memory to leak - the Android operating system would like to clear from memory "old" activities when it decides it's the time to do so (You can't control it manually).
In that case - the garbage collector would try to free the activity / activities from memory, but because something (your array of references to activities) is holding a reference to it - it can't be garbage collected, so it can't free it from memory- and that's a sample of a memory leak.
This document describes how to avoid memory leaks:
http://android-developers.blogspot.co.uk/2009/01/avoiding-memory-leaks.html
Try rotating the device a couple of times and see what happens- you'll eventually run out of memory because you're still holding a reference to previous contexts which the GC can't clear.
Related
I'm trying to get better at hunting down memory leaks in Android.
I have discovered the Android Profiler and learned how to perform a heap dump and how to determine if there are too many instances of a given object in memory.
I have read that one of the ways to get to the root of why an unwanted object is still hanging around is to highlight it and "look at what objects are still holding references to it and trace your way back to the original cause."
So... in this screenshot you can see the undesirable situation: I have three instances of MainActivity... and all three of them have a number in the "depth" column signaling they are really leaks.
If the object in question were a class of my own creation, then the process would be more straight-forward, but since we're dealing with an actual Activity here, when I highlight any one of the three, there is a massive list of objects referencing it (the list goes far beyond the screenshot).
Surely most of these are normal/benign references -- How am I supposed to tell which ones are worth investigating?
What are the clues? Is it the " this$0 " ? Or the massive number in the retained column? A depth number matching the object in question? I'm just guessing at this point.
Surely I'm not expected to go through the entire list mulling to myself, "Nope... can't be that one... that's a normal part of Android Framework X,Y, and Z..."
I'm trying to get better at hunting down memory leaks in Android.
I will give couple of examples but first, due to the number of questions you asked that is not related to your topic
I will first explain what you see in "Instance view";
Depth: The shortest number of hops from any GC root to the selected instance.
0 is for "private final class" or static members
if it's blank it's going to be reclaimed - which is harmless for you
Shallow Size: Size of this instance in Java memory
Retained Size: Size of memory that this instance dominates (as per the dominator tree).
Is it the this$0?
this$0 is a synthetic variable generated by the compiler which means "one level out of my scope", it's a parent object of a non-static inner class.
How am I supposed to tell which ones are worth investigating?
It depends, if the depth is 0 and it's your code - investigate, maybe it's a long running task with bad end condition.
When analyzing a heap dump in the Memory Profiler, you can filter profiling data that Android Studio thinks might indicate memory leaks for Activity and Fragment instances in your app.
The types of data that the filter shows include the following:
Activity instances that have been destroyed but are still being referenced.
Fragment instances that do not have a valid FragmentManager but are still being referenced.
In certain situations, such as the following, the filter might yield false positives:
A Fragment is created but has not yet been used.
A Fragment is being cached but not as part of a FragmentTransaction.
Filtering a heap dump for memory leaks.
Techniques for profiling your memory
While using the Memory Profiler, you should stress your app code and try forcing memory leaks.
One way to provoke memory leaks in your app is to let it run for a while before inspecting the heap.
Leaks might trickle up to the top of the allocations in the heap.
However, the smaller the leak, the longer you need to run the app in order to see it.
You can also trigger a memory leak in one of the following ways:
Rotate the device from portrait to landscape and back again multiple times while in different activity states. Rotating the device can often cause an app to leak an Activity, Context, or View object because the system recreates the Activity and if your app holds a reference to one of those objects somewhere else, the system can't garbage collect it.
Switch between your app and another app while in different activity states (navigate to the Home screen, then return to your app).
A growing graph is a big indicator
If you observe a trend line that only keeps going up and seldomly goes down, it could be due to a memory leak, which means some pieces of memory cannot be freed. Or there’s simply not enough memory to cope with the application. When the application has reached its memory limit and the Android OS isn’t able to allocate any more memory for the application, an OutOfMemoryError will be thrown.
Turbulence within a short period of time
Turbulence is an indicator of instability, and this applies to Android memory usage as well. When we observe this kind of pattern, usually a lot of expensive objects are created and thrown away in their short lifecycles.
The CPU is wasting a lot of cycles in performing Garbage Collection, without performing the actual work for the application. Users might experience a sluggish UI, and we should definitely optimize our memory usage in this case.
If we are talking about Java memory leaks
public class ThreadActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
new DownloadTask().start();
}
private class DownloadTask extends Thread {
#Override
public void run() {
SystemClock.sleep(2000 * 10);
}
}
}
Inner classes hold an implicit reference to their enclosing class, it will generate a constructor automatically and passes the activity as a reference to it.
The above code is actually
public class ThreadActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
new DownloadTask(this).start();
}
private class DownloadTask extends Thread {
Activity activity;
public DownloadTask(Activity activity) {
this.activity = activity;
}
#Override
public void run() {
SystemClock.sleep(2000 * 10);
}
}
}
In a normal case, the user opens the activity wait 20sec until the download task is done.
When the task is done the stack released all the objects.
Then the next time the garbage collector works he will release the object from the heap.
And when the user closes the activity the main method will be released from the stack and the ThreadActivity also reclaimed from the heap and everything works as needed without leaks.
In a case that the user closes/rotate the activity after 10sec.
The task is still working that means the reference for the activity still alive and we have a memory leak 💣
Note: when the download run() task is done the stack release the objects. so when the garbage collector works next time the objects will be reclaimed from the heap because there is no object referenced on it.
related Youtube playlist
And https://square.github.io/leakcanary/fundamentals/ is great.
I have a Fragment which has a RecyclerView.
In this RecyclerView, I may occasionally download and display images (loaded with Glide into ImageView.
So when I open the Fragment, used memory may sometimes jump from around 30MB to around 100MB or even more.
After the Activity that is holding the Fragment is finished, the memory does not free up. It stays the same as before.
I checked Glide documentation and apparently we don't have to worry about freeing up Bitmaps in RecyclerView. This is a huge issue, because app often crashes due to OOM because of this.
How should I correctly handle freeing up memory when Fragment is removed?
Edit: another observation
Another thing I noticed is that if I finish the Activity and then start the same Activity again. Memory will jump back down for a moment and then back up to 100MB, which leads me to believe that the memory is cleared before launching the Fragment again.
Garbage Collection is sometimes a painful issue in Android.
Most developers fail to consider this issue and just keep developing without any sense of resource allocation.
This will of course cause memory problems such as leaks, OOM and unnecessary resource binding. There is absolutely no automatic way to free up memory. You can not, under any circumstances, rely solely on the Garbage Collector
Whenever you pass the Fragment's or Activity's onDestroy() method, what you can and should do is erase any construct that shall no longer be required in the application. You can do the following :
Avoid anonymous instances of listeners. Create listeners and destroy them when you no longer need them.
Set all the listeners (be them click, longclick, etc) to null
Clear all variables, arrays. Apply the same procedure to all the classes and subclasses contained inside the Activity/Fragment
Set the variable to null whenever you perform any of the previous steps on that given class (applies to all variables)
What I ended up doing was creating an interface like
public interface clearMemory(){
void clearMemory();
}
and implementing it on every class, be it Activity, Fragment or a normal class (includes adapters, custom views, etc).
I would then call the method whenever the class was to be destroyed (because the app was being destroyed or whenever I felt need to do so. Careful not to dispose in normal runtime)
#Override
public void onDestroy(){
clearMemory();
}
public void clearMemory(){
normalButtonOnClickListener = null;
normalButton.setOnClickListener(null);
normalButton = null;
myCustomClass.clearMemory(); // apply the interface to the class and clear it inside
myCustomClass = null;
simpleVariable = null;
...
}
By implementing this in a systematic way, my applications' memory management has become easier and leaner. One can then then know/control exactly how and when the memory is disposed.
This is adding on to Ricardo's answer.
You can add the following code to initiate garbage collection in Android:
Runtime.getRuntime().gc();
Note: Call this function after you've made all local variables null. Execution of this code doesn't guarantee that the system will garbage collect on your app, it merely hints that it might be a good time to do it.
I've used this in all my activities' onDestroy(), and it always seems to work when I want it to.
Give it a try, it might help you out.
I have activity A, which launches activity B via an intent. Activity A has no references to Activity B, there are also no references to Activity B in the Application singleton I am using.
When I create Activity B, several thousand objects are created. That's okay, it's an activity with a very populated ListView with lots of images.
But, when I press the back button and return to Activity A, only about a dozen of the several thousand objects are released. onDestroy() is also called for the activity. I'm using DDMS to view the heap info, and am pressing 'Cause GC' several times to force it to free memory.
I've done the same test on other apps (that use list views too) and 100% of their objects are destroyed on pressing the back button then 'Cause GC', so it's certainly not a bug.
Any advice please? :-) I've read the material in the android docs about leaking contexts, but that's not helpful since i'm not referencing the activity (or anything in it) being destroyed elsewhere. Also, I have many other activities which work the same way, and don't release all memory on destroy. I must be missing something obvious?
Edit: I just realized i'm using AsyncTasks which have references to the activity (either passed as arg into doInBackground() or accessible via outerClass.this. Could they be hanging around in the thread pool, even after onPostExecute() ?
Edit: It leaks even if I go back before running any asynctasks :-(
Edit: No leak before running asynctasks if I remove admob code, but still leaks in the activites which do use asynctasks.. so asynctask is still a good candidate :-)
I believe there's a bug in the ListView implementation. Take a look at this question: Android: AlertDialog causes a memory leak.
Here's a bug report: http://code.google.com/p/android/issues/detail?id=12334. It's declined but in my opinion it must be reopened.
I'm getting an OutofMemoryError for my android application, and am a bit confused as to whats going on. Basically what happens is, I'm able to run it the first few times, but when I try to quit out of it and then open it again quickly and repetitively, I get an out of memory error.
I've tried researching this topic, and have found that the recycle() method has commonly been the problem. However, I've called the recycle method on each of the bitmaps (which are stored in an object container, stored in an arraylist), but was still getting the problem.
After doing this, I tried using the Eclipse Memory Analyzer to look at heap dumps, when I came across something weird. After quitting out of the activity (back into the launcher activity, and then opening up the activity again via a button, I took screenshots of the heap dump using the memory analyzer. It turns out, with each time I quit and re-entered the activity, another instance of the activity object was being created, and the old ones weren't being released, even though the onDestroy() method was being called (which also had the recycle/cleanup code.
I then tried overriding the finalize method to see if it was being called when the activity quit out back into the launcher activity, but it wasn't being called. I read on some other stackoverflow threads that finalize() isn't always called, so in the end, I'm still not sure whats going on.
Ultimately, my question is this:
How am I supposed to ensure that the Activity object (the activity object itself, not the stuff created from the activity) is released after quitting out from the activity into another activity?
Sounds like you application suffers from memory leaks, i recommend you to follow the links below:
Avoiding Memory Leaks
Memory management for Android Apps
One option is setting the launch mode to singleInstance or singleTask in your manifest file. This would make sure that another instance of the Activity is not created.
Documentation Example
One way to release your object of activity is calling it onDestoy() method..Take an object of your activity make it public static and make it null in onDestroy()
Public static Your_activity obj;
And then in onCreate method initalize obj by this
obj=this;
and in onDestroy() method do this:
obj= null;
I am finding that performance degrades after one or more screen rotations, and I presume that this is likely to be because an App's main Activity is destroyed and recreated each time the screen is rotated and that my app must be leaking memory when that happens.
I have read that, contrary to what one might expect, not all the objects created by an app's main Activity (or in classes called by that Activity) are destroyed when the activity is destroyed. Specifically, I think I have read (although I can't now find where) that if the View uses a large bitmap member object then the Activity's onDestroy() method should be over-ridden and the bitmap should be explicitly recycled.
Are there other objects that need to be destroyed or removed when the Activity is destroyed? What about Listeners? Is there a comprehensive tutorial or guide on this subject?
Is there a comprehensive tutorial or
guide on this subject?
Not really.
Are there other objects that need to
be destroyed or removed when the
Activity is destroyed? What about
Listeners?
Bitmaps are unusual, in part because they use memory outside of the 16MB heap, if I understand the byzantine Android memory model correctly.
Beyond large bitmaps, the biggest thing you really need to worry about are things that prevent normal garbage collection from working. Anything that holds onto the activity, directly or indirectly, from a static context will keep the activity from being garbage collected. Examples include:
static data members on classes (e.g., you rig up your own listener framework with one of your services, so your service holds onto a listener which holds onto your activity)
threads (e.g., you manually fork a background thread and do not terminate it)
Note that putting android:configChanges="orientation" in the Manifest prevents the Activity from being destroyed when the screen is rotated. So I no longer need to worry about whether I need to destroy or remove individual bitmaps or other objects! (Thanks to Ribo for pointing this out on another thread.)