Android memory leak - deadly embrace - android

Initially I didn't pay a lot of attention to the possibility of memory leaks in Android, given the nature of managed code / garbage collection and so on. I'm thinking this might have been a bit naive. Here's the question:
Say there is an activity - MyActivity. When the OS starts it, in its onCreate() this instantiates another class (MyOtherClass) and keeps a reference to it. However say the instance of MyOtherClass also keeps a reference to the context - which happens also to be a reference to the instance of MyActivity.
Now something happens - say the screen gets rotated. OS calls the activity onDestroy() and drops the reference to that old instance of MyActivity. However, that activity instance still has a reference to an instance of MyOtherClass, which in turn has an instance to the activity.
So, am I right in thinking those two classes are going to keep each other alive for evermore?
If so, I guess possible answers are (a) don't keep a context reference, get it another way, or (b) in the activity onDestroy() drop any references it has to anything else, then it all ought to just collapse.

Java wouldn't allow cyclic links to keep each other alive (in memory). However if you have declared references static or created singleton style objects, Java won't help you there.
A good start might be reading avoiding memory leaks.

Related

MemoryLeak through onConfigurationChanged()

I have an AsyncTask which I need to "restart" if the user does configurations such as Switch Color.
When he do so I start the AsyncTask like this:
myWorkerClass.clearMemory();
myWorkerClass = new WorkerClass(getApplicationContext(), gv, searchbar, width, scaleButtonText);
myWorkerClass.execute();
In the AsyncTask I add a onTextChangeListener to my EditText!(Which causes the MemoryLeak later).
To prevent MemoryLeaks I have a Method in my AsyncTask which removes the onTextChangedListener:
public void clearMemory() {
searchbar.removeTextChangedListener(myTextWatcher);
}
Everything works fine except when I rotate my device. When I rotate my Device I do only this in onConfigurationChanged:
myWorkerClass.clearMemory();
myWorkerClass = new WorkerClass(getApplicationContext(), gv, searchbar, width, scaleButtonText);
myWorkerClass.execute();
As you can see I do exactly the same thing as if the user changes a Color. But at rotating device I'm leaking Memory, at switching Color I'm not!
This is after switching the Color:
This is after rotating the Screen a few times (remember I do exactly the same as at switching color:
These are my Leak Suspects from the Heap Dump:
This is my dominator tree:
Why do I know the onTextChangeListener is the Problem?
Because if I comment adding a onTextChangedListener to my EditText out, everything works fine. No Memory Leaks.
My Question:
Why does a Rotation Change leak Memory and a Color Change does not when I start the asynctask the exact same way and do exact the same things within the asynctask?
I searched a little bit: http://developer.android.com/guide/topics/resources/runtime-changes.html
But I can't figure out if that is my Problem. The Rotation must do something different, like creating a new activity because of that creating a new reference to my edittext. And because of that he can't remove the old onTextChangeListener.
Please understand. I don't want to make my whole code public. But I think this isn't necessary anyway in this case.
The Rotation must do something different, like creating a new activity because of that creating a new reference to my edittext.
exactly, it destroys your current activity and creates a new one. If searchbar is a member variable of your AsyncTask then consider putting it into WeakReference:
WeakReference<SearchBar> searchbarPtr;
then access using searchBarPtr.get(), but check if its null, if so then it means it was garbage collected due to config change.
Also remember to not make your AsyncTask an inner class of you activity. If it is nested then make it static. Otherwise your asynctask will keep reference to your activity and it will prevent it from being destroyed - until its thread ends.
Unfortuanately making it all work corectly in all situations can be quite difficult and time consuming.
Hopefully no one will suggest preventing destruction of your activity through android:configChanges, implementing correct behaviour of your activity during rotation will prevent it from crashing/leaking in less common activity lifecycle moments which cannot be prevented by android:configChanges.
In android, the rotation destroys your current activity to start a new one.
To avoid it, you can add android:configChanges="orientation|screenSize" in your manifest file.
Below are tips to avoid memory leaks on Rotation change
Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself)
Try using the context-application instead of a context-activity
Avoid non-static inner classes in an activity if you don't control their life cycle, use a static inner class and make a weak reference to the activity inside. The solution to this issue is to use a static inner class with a WeakReference to the outer class, as done in ViewRoot and its W inner class for instance
A garbage collector is not an insurance against memory leaks
Source: Avoiding memory leaks

Is it acceptable to maintain an instance of Context in a class not derived from Activity?

I am developing an application where I've passed the Activity's context into a class derived from Object.
Is there anything wrong with doing this?
Maintaining an instance of a Context like that of an Activity or Service is going to open up ways for memory leaks.
However, keeping a reference to the instance returned by getApplicationContext() should be harmless.
There's nothing inherently wrong at all. Every View class does that, for instance.
The only danger is maintaining a reference to an Activity after it is destroyed. This is a common source of memory leaks. See the blog post Avoiding memory leaks for more information about this.
View subclasses avoid leaking because references to the views themselves generally go away when the activity is destroyed. If your class instance that is maintaining a reference does not go away like that, then you need to arrange for the reference to go away. One option is to override onDestroy for your activity and do some clean-up there. Another is to use a SoftReference instead of a hard reference to the context.

Difference between static reference and reference inside Application class?

Suppose I have a reference to an instance of a class, which doesn't have any direct/indirect reference to problematic objects (like context,views,...). Are there any differences between using this reference in a static reference and using it inside the class that extends the Application class?
I mean, in both ways the referenced object will be freed only when the process is killed (or when there are no references to it), right? Maybe there is a difference when using multiple processes?
One slight difference is that the Garbage Collector will first destroy static references bound in Activities (or Services) in case of intense memory shortage if it was in a situation of choosing between a static reference and a reference inside Application class. This situation happens because when the Activity (or Service) is destroyed, it will leave the static variables without references (if they have no other reference except the one described above), so they can be collected by the GC. Even if the VM reinitialize the Activity (or Service), those static references will take the initial value losing any updates that may have been occurred. As a general rule of thumb, if you want to be sure that the static variables will be persistent:
Do not reference them from Activities (or Services) since there is a chance that they might be destroyed in case of memory shortage.
Reference them from Activities or Services but handle the situation of them being destroyed manually (for example, with the onSavedInsanceState method of Android) just like will you do with non static references.
EDIT Here is an explanation of why is this happening:
Static references are bound to the class loader of the class
that first initialized them. This means that that if a static variable
inside any class has been initialized by an activity, when that
activity is destroyed also its class might be unloaded and so the
variable becomes uninitialized. While if the variable is initialized
by the application class, it’s life is the same as the application
process so we’re sure that it will never become uninitialized again.
That’s why I chose to initialize all the singletons in the
MyApplication class.
found in this link.
I believe the article cited in the other answer by #Angelo is very wrong (to say the least) and caused much confusion : the classes in android are unloaded on a per process basis not on a per class basis. That is if your app is killed and the classes are unloaded you lose all static state - if not no. That is what I make of #fadden's answers at least :
Is it still the case that Android never unloads classes?
Android: When do classes get unloaded by the system?
Now your question is a bit vague... A static reference is not the same as a non static wherever it's used. If you mean that both variables are static then there is no difference if they are in an activity, application or whatever instance - whenever the class is loaded and the variables take some value they will remain so till the classes are unloaded. Not sure if there is a specified order in unloading the classes - or if that would matter.

Will this dialog leak memory?

This is not my code. I just arrived at this site and am doing code review.
They have a class which is an extension of Dialog.
It has been defined as a singleton.
On the first call the context is passed to the getInstance method.
It instantiates the class passing the received context to the "super" within the constructor.
Then it saves it - same as in any singleton.
It then displays the dialog. After user interaction it starts a new activity and closes the dialog via "closeDialog".
However, it is still alive since the static holder for the instance is still there.
Will this then hold on to the activity that created it (and was passed on the "getInstance" call and into the "super()" when creating the instance)?
They keep the instance alive because they then use it for calls from other places and have values that need to be carried over.
I know this code stinks but I want to be sure that it does leak memory (the first activity) before I make them re-write it (or re-write it myself - which is more likely).
Yes it could. If the code starts other activities, then yes. If only the one activity is ever used, then most likely not. The reason being, dialogs must be instantiated with an activities context (it'll crash with the Application context). If that activity is set to be destroyed, garbage collection won't clean it up until all references to it are destroyed. If this singleton dialog lives outside the activity (which should be the case), then it'll continue referencing the activity and prevent GC from cleaning it up. You can read more about leaking contexts here: Avoiding memory leaks
As you stated the code is bad, and using a singleton dialog like that is just plain wrong (whether it leaks or not). There are better ways of maintaining data between states.
Instead of creating and holding Dialog inside Singleton class, build the dialog in that Singleton class but return Dialog instance to the caller class. So calling Activity will be responsible for dismissing Dialog and i believe there will not be memory leak.

Complex activity issues

I think my problem is because I'm misusing inheritance. I've got 4 activities, all extend BaseActivity which shares common code (onClick, onItemClick, static and non-static methods). Each activity get it's data from web - that includes images. When I use whole app for longer period of time I've got memory leak errors (VM won't let us allocate xxx bytes) and app crushes.
If I properly understand - it's because by extending these 4 activities I make them something like inner classes of Base Activity - that's why their onDestroy() methods aren't invoked when I switch between them. Moreover - GC don't reclaim any RAM and heap is beeing clogged. BaseActivity is holding all the data (for example images) thus allowing showing them when Back button is clicked with no need to recreating the data.
If that's true - another option is make them seperate by using helper classes to share common code - but then, when I will be switching between activities - they will be downloading it's data over and over.
I'm I right and is there any solution ?
So, it's hard to answer without seeing some code, but extending the Activity class shouldn't really be causing memory leaks. More than likely you're hanging on to a lot of unnecessary data from your web requests. You said you were downloading images, right? I'd start by looking there.

Categories

Resources