I have a question that looks very easy and simple but I am bit confused. My question is, in Android application I am making static reference of activity for some purposes. And in onDestroy() I am making that activity reference null while assigning null value explicitly. Is it good? Will it be eligible for garbage collection? will it also cause memory leak? Please help me in this regard.
This is the code I am using for activity reference in onCreate() method
mInstance = this;
And this is how in onDestroy() I am assigning null value
#Override
protected void onDestroy() {
super.onDestroy();
mInstance = null;
}
I'm not an Android developer, so I'll answer your question without taking into account that.
Yes, the space allocated by your Activity in the heap will be collected (may be collected) once no more references to it exists. Like every other object in Java.
Being static or not doesn't change that.
Although honestly I don't understand why
mInstance = this;
Could you explain in more details?
This isn't thread safe at all, so be careful if you're working on a concurrent environment.
Yes if you nullify it will be garbage collected, but assigning an Activity to a static variable is an anti-pattern and must be avoided at all costs, even if you eventually nullify it, because this is easiest way to leak an Activity.
In fact, Android Studio should already be giving you a warning about it.
Here you have some literature to avoid leaking memory.
People will hate me for this but in my own modular architecture i like to use them on android. Yes it is a memory leak if you do not use them properly but it saves time and time means $$$ in my book. When i need to parse a Java Object from an activity to another activity there is diferent options. putExtra(JsonString), putExtra(Parseable), putExtra(Serializable). But i just like to create a new static file to hold all the objects i need temporary with a static public function to nullify all of them after getting them in the other activity. Be carefull if you do this.
Related
I have the following 2 lines of code in my MainActivity class passing a value:
RecyclerView mRecyclerView = findViewById(R.id.act_recyclerview);
new LoadText(this,mRecyclerView).execute();
In my LoadText class, I am consuming as follows:
private Context mContext;
private RecyclerView mRecyclerView;
public LoadText(Context context, RecyclerView recyclerView){
this.mContext=context;
this.mRecyclerView=recyclerView;
}
My code works fine, however Android Studio is warning of a resource leak when I hover over mContext and mRecyclerView. I have looked for solutions to similar problems like mine and it was suggested to pass the value via a constructor, which is what I am doing so I am not sure I understand why.
This is a warning, which means that the system knows that something might be wrong, but can't say 100% for sure.
In this case, the question is how long your LoadText object lives for. If it lives longer than the Activity or the RecyclerView that you pass to it, your code will cause a memory leak: the LoadText has a strong reference to the Activity, which will prevent it from being garbage collected.
If you, as a human, know that your LoadText object will never live longer than the Activity (or will only do so for a brief amount of time), then you can safely ignore this warning. If, on the other hand, the LoadText object lives for a long time, it could potentially keep your activity alive forever.
Practically speaking, leaking a single Activity isn't the end of the world. But if you do things like this a lot, eventually your app will run out of memory and crash.
It's also possible that the zombie Activity will wind up executing code that you don't expect (maybe the LoadText class calls a method on it), which could lead to undesirable behavior or a crash.
In this case I am trying to understand some concepts related to memory leaks in Android. Though it is a frequent question, I am more interested on a real justification rather than a simple answer like "do not keep a reference to the activity".
These are the pages I've been reading so far:
link1: Garbage-Collection Roots—The Source of All Object Trees
link2: Memory leaks in Android
link3: Memory leaks in Android
and my conclusion so far is that the only way to have memory leaks with activities is when a component has a reference to an Activity and the lifecycle of this component is beyond the activity's lifecycle. The time you have a memory leak depends on the lifecycle of that component.
With that being said, I found this discussion with Jake Wharton related to Dagger 2 in an MVP architecture, where he wrote:
There is no leak. If the activity has outgoing references to
dependencies and there are no incoming references to the activity it
will be garbage collected.
As far as I know, if I have an activity which has a reference to a presenter which has a reference to a view interface (the implementation is the same activity), and then the activity is being recreated with a new presenter, then I do not see the reason why we can have memory leaks: the old activity and presenter are not longer reachable and thus they are potentially garbage collected. The only way I can have memory leak is if the presenter or any component inside the presenter has a lifecycle beyond the activity's lifecycle.
My questions are:
Am I missing something here?
Does having a reference to an activity mean I will have memory leaks? If that so, then does it mean the activity is considered a Garbage-Collection Root
It took me time to get back to this question and get all the information possible to understand how this works and see if the statement "if you have an object referring to an Activity which has been replaced by another activity, then you have a memory leak" is true.
Firstly, I decided to run some code to see the memory's behaviour. I used a simple MVP project I have.
The first thing I have done is to keep a reference to the activity in my presenter after the onDestroy method has been called:
public abstract class BasePresenter<T> {
//Activity or Fragment attached to Presenter
protected T view;
public void onViewCreated(T view) {
this.view = view;
}
public void onStart() {
}
public void onResume() {
}
public void onPause() {
}
public void onStop(){
}
public void onDestroyed() {
// view = null;
}
}
Then I turned on the "do not keep activities in memory" option and recreated the activity a couple of times.
When I dumped the memory I saw multiple instances of that activity, but after calling the garbage collector with the android memory profiler option they disappeared (as you know the GC is not called every time due to performance issues, just when it is needed).
So in this case the statement "if you have an object referring to an Activity which has been replaced by another activity, then you have a memory leak" is not true, or at least it is not complete to be true. In order to get a memory leak, that dependency graph needs to be referenced by a GC root.
Then I decided to uncomment that line in onDestroy:
public void onDestroyed() {
view = null;
}
and have a static reference to a view in my fragment (views have a reference to the activity where they are created)
private static View viewLeak;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
progressBar = view.findViewById(R.id.progress);
if(viewLeak == null){
viewLeak = progressBar;
}
}
Again, I repeated the process of recreating the activity and in this case I had multiples instances of the same activity (two instances: one which was actively used and another one referenced by the static view). Of course I called the garbage collector but that extra instance of the activity stayed in memory. What changed here is that in this case we have a GC root which is the static variable:
Static variables are referenced by their classes. This fact makes them de facto GC roots. Source
Of course, there are multiple cases where you can get a CG root and thus, multiple cases where you can get memory leaks.
I hope this helps you to clarify some concepts related to memory leaks in Java as it did to me.
Other sources that were useful to understand this are:
LINK1, LINK2, LINK3
NEW CONTENT:
This is a video from google I/O talking about memory leaks. Please, pay attention when he says "long-live objects having a reference to an Activity" - minute 25:30.
Suppose you have an object A that has a reference to Activity B. Now suppose you finish the Activity B. You can be sure that B is ready to be garbage-collected.
Now suppose you manually call the GC. Will it recycle the Activity B? No! Why? Because there's one object referring to it (object A).
This is how a memory leak is born.
I am constantly struggling with identifying memory leaks. I guess I have several memory leaks in my project circular progress view.
One of my guesses is I have a memory leak in the internal class FadeRunnable.
But to be honest I don't know exactly how to find out if this is exactly the source of the problem. Well, when I do the usual scenario and switch the orientation I see an increase of the memory usage as shown below. And if I comment out the usage of the FadeRunnable class the steps are smaller (but still there, so I guess that's not the only leak)
Once I analyze the heap dump, I see something. But actually I don't know what the values mean. The things I do is
Change orientation many times
Open heap dump and sort by 'Retained Size'
Now when I click on "CircularProgressView' I see 8 rows in the right area. I guess this means there are 8 instances of the 'CircularProgressView' leaked and living somewhere as orphan in the memory.
Is this correct? If so, how can I find out in the dump information (I guess somewhere in the lower pane) where this object is saved/held.
I would love to have a step-by-step explanation how to find out if and which object is leaking some memory.
All of the code of the suspected view can be found in this class.
https://github.com/momentummodules/CircularProgressView/blob/master/circularprogressview/src/main/java/momentum/circularprogressview/CircularProgressView.java
But also feel free to check out the full project for deeper insight and if you want to play around with it.
Thanks in advance!
UPDATE
The code link from above shows the fixed code of the mem-leaking inner class. The following snippet shows the original mem-leaking code that should never be used like that
/**
* Mem-leaking code, for fixed code see repository link
* https://github.com/momentummodules/CircularProgressView/blob/master/circularprogressview/src/main/java/momentum/circularprogressview/CircularProgressView.java
*/
public class CircularProgressView extends View
{
...
private Thread fadeThread = null;
...
...
class FadeRunnable implements Runnable
{
#Override
public void run()
{
...
}
}
...
...
private void startFade(boolean fadeIn)
{
// check existing
if(this.fadeThread != null)
{
// check if fade is already running
switch(this.fadeThread.getState())
{
case TERMINATED:
case NEW:
this.fadeThread = null;
break;
case RUNNABLE:
case BLOCKED:
case TIMED_WAITING:
case WAITING:
return;
}
}
// create new
this.fadeThread = new Thread(new FadeRunnable(fadeIn, this.fadeTime));
this.fadeThread.start();
}
}
Yes, you do have a memory leak in FadeRunnable class.
Every instance of inner class contains implicit reference to its outer class, accessible through OuterClass.this operator. In your project, when you execute the FadeRunnable and then trigger reconfiguration by orientation change, the whole activity and your CircularProgressView contained within get recreated, but the FadeRunnable from previous is still alive (allocated) and, because of it holding implicit reference to its outer CircularProgressView class, the view continues to live also, that's why after several reconfigurations you have 8 instances of CircularProgressView allocated in memory, and that gets worse - every View keeps a reference to it's context, and this cannot be freed also, resulting in bad memory leaks.
Runnables, Handlers and similar objects that can out-live their enclosing activities, fragments, views etc. should be declared as standard classes or STATIC inner classes (a static inner class doesn't hold implicit reference to its outer class), and shouldn't keep references such as Context, View etc., instead you can keep a WeakReference<> so when your Activity is recreated through config change, the View can be destroyed and freed by garbage collector.
This is a very informative article on the subject, I strongly suggest reading it.
I guess you have the correct direction there. This FadeRunnable is certainly not cool. Even if you have other memory leaks, you defo should check this out.
In general what you should really be doing in a view is quite different, specially that views already have facilities to deal with timing and animation without the need for threads.
I'll suggest you what I believe is a simpler and cleaner approach to animate stuff on views.
Start by removing your runnable and thread completely.
then to start an animation you do:
ValueAnimator animation = ValueAnimator.ofFloat(0, 1);
animation.setDuration(500);
animation.addUpdateListener(animationUpdate);
animation.addListener(animationUpdate);
animation.start();
and then you need those listeners
// this gets called for every animation update,
// inside this call you update `CircularProgressView.this.fadeAlpha`
private final ValueAnimator.AnimatorUpdateListener animationUpdate = new ValueAnimator.AnimatorUpdateListener() {
#Override public void onAnimationUpdate(ValueAnimator animation) {
// this fraction varies between 0f and 1f
float fraction = animation.getAnimatedFraction();
// ... do your calculation
ViewCompat.postInvalidateOnAnimation(CircularProgressView.this);
}
};
// this is an optional one only if you really need
// in that you get notified when the animation starts and ends
private final Animator.AnimatorListener animationListener = new AnimatorListenerAdapter() {
#Override public void onAnimationStart(Animator animation) {
// anything u need goes here
ViewCompat.postInvalidateOnAnimation(CircularProgressView.this);
}
#Override public void onAnimationEnd(Animator animation) {
// anything u need goes here
ViewCompat.postInvalidateOnAnimation(CircularProgressView.this);
}
};
and that's about it.
On the topic of actual memory leak analysis I'll suggest you to from now on and forever use the leak canary library: https://github.com/square/leakcanary it's a great tool to help us (developers) track memory leaks.
edit:
Why are you having a memory leak on this animation?
It's quite simple:
on startFade(boolean); you create a new thread and a new runnable
the runnable have a reference to the view (because it's an non-static inner class)
the thread have a reference to the Runnable, so can run it.
the framework destroy the view, because it's not part of the UI anymore (rotation, back button)
the thread is still running, with the runnable still looping, with the View object still not destroyed because the Runnable references it.
the view Object have an instance of Context, and this context is the Activity.
So at the end of this sequence your activity will not be garbage collected by the GC, AKA: Memory Leak !
I have a question specific to how the classloading / garbage collection works in Android. We have stumbled upon this issue a few times now, and as far as I can tell, Android behaves different here from an ordinary JVM.
The problem is this: We're currently trying to cut down on singleton classes in the app in favor of a single root factory singleton which sole purpose is to manage other manager classes. A top level manager if you will. This makes it easy for us to replace implementations in tests without opting for a full DI solution, since all Activities and Services share the same reference to that root factory.
Here's how it looks like:
public class RootFactory {
private static volatile RootFactory instance;
#SuppressWarnings("unused")
private Context context; // I'd like to keep this for now
private volatile LanguageSupport languageSupport;
private volatile Preferences preferences;
private volatile LoginManager loginManager;
private volatile TaskManager taskManager;
private volatile PositionProvider positionManager;
private volatile SimpleDataStorage simpleDataStorage;
public static RootFactory initialize(Context context) {
instance = new RootFactory(context);
return instance;
}
private RootFactory(Context context) {
this.context = context;
}
public static RootFactory getInstance() {
return instance;
}
public LanguageSupport getLanguageSupport() {
return languageSupport;
}
public void setLanguageSupport(LanguageSupport languageSupport) {
this.languageSupport = languageSupport;
}
// ...
}
initialize is called once, in Application.onCreate, i.e. before any Activity or Service is started. Now, here is the problem: the getInstance method sometimes comes back as null -- even when invoked on the same thread! That sounds like it isn't a visibility problem; instead, the static singleton reference hold on class level seems to actually have been cleared by the garbage collector. Maybe I'm jumping to conclusions here, but could this be because the Android garbage collector or class loading mechanism can actually unload classes when memory gets scarce, in which case the only reference to the singleton instance will go away? I'm not really deep into Java's memory model, but I suppose that shouldn't happen, otherwise this common way of implementing singletons wouldn't work on any JVM right?
Any idea why this is happening exactly?
PS: one can work around this by keeping "global" references on the single application instance instead. That has proven to be reliable when one must keep on object around across the entire life-time of an app.
UPDATE
Apparently my use of volatile here caused some confusion. My intention was to ensure that the static reference's current state is always visible to all threads accessing it. I must do that because I am both writing and reading that reference from more than one thread: In an ordinary app run just in the main application thread, but in an instrumentation test run, where objects get replaced with mocks, I write it from the instrumentation thread and read it on the UI thread. I could have as well synchronized the call to getInstance, but that's more expensive since it requires claiming an object lock. See What is an efficient way to implement a singleton pattern in Java? for a more detailed discussion around this.
Both you (#Matthias) and Mark Murphy (#CommonsWare) are correct in what you say, but the gist seems lost. (The use of volatile is correct and classes are not unloaded.)
The crux of the question is where initialize is called from.
Here is what I think is happening:
You are calling initialize from an Activity *
Android needs more memory, kills the whole Process
Android restarts the Application and the top Activity
You call getInstance which will return null, as initialize was not called
Correct me if I'm wrong.
Update:
My assumption – that initialize is called from an Activity * – seems to have been wrong in this case. However, I'll leave this answer up because that scenario is a common source of bugs.
I have never in my life seen a static data member declared volatile. I'm not even sure what that means.
Static data members will exist until the process is terminated or until you get rid of them (e.g., null out the static reference). The process may be terminated once all activities and services are proactively closed by the user (e.g., BACK button) and your code (e.g., stopService()). The process may be terminated even with live components if Android is desperately short on RAM, but this is rather unusual. The process may be terminated with a live service if Android thinks that your service has been in the background too long, though it may restart that service depending on your return value from onStartCommand().
Classes are not unloaded, period, short of the process being terminated.
To address the other of #sergui's points, activities may be destroyed, with instance state stored (albeit in RAM, not "fixed storage"), to free up RAM. Android will tend to do this before terminating active processes, though if it destroys the last activity for a process and there are no running services, that process will be a prime candidate for termination.
The only thing significantly strange about your implementation is your use of volatile.
Static references are cleared whenever the system feels like it and your application is not top-level (the user is not running it explicitly). Whenever your app is minimized and the OS wants some more memory it will either kill your app or serialize it on fixed storage for later use, but in both cases static variables are erased.
Also, whenever your app gets a Force Close error, all statics are erased as well. In my experience I saw that it's always better to use variables in the Application object than static variables.
I've seen similar strange behaviour with my own code involving disappearing static variables (I don't think this problem has anything to do with the volatile keyword). In particular this has come up when I've initialized a logging framework (ex. Crashlytics, log4j), and then after some period of activity it appears to be uninitialized. Investigation has shown this happens after the OS calls onSaveInstanceState(Bundle b).
Your static variables are held by the Classloader which is contained within your app's process. According to google:
An unusual and fundamental feature of Android is that an application
process's lifetime is not directly controlled by the application
itself. Instead, it is determined by the system through a combination
of the parts of the application that the system knows are running, how
important these things are to the user, and how much overall memory is
available in the system.
http://developer.android.com/guide/topics/processes/process-lifecycle.html
What that means for a developer is that you cannot expect static variables to remain initialized indefinitely. You need to rely on a different mechanism for persistence.
One workaround I've used to keep my logging framework initialized is for all my Activities to extend a base class where I override onCreate and check for initialization and re-initialize if necessary.
I think the official solution is to use the onSaveInstanceState(Bundle b) callback to persist anything that your Activity needs later, and then re-initialize in onCreate(Bundle b) when b != null.
Google explains it best:
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
Is it possible to create an object which will be alive till the JVM is not shut down? Or is there any java objects which remains alive till the JVM is not shutdown.
You can be fairly certain that a static field will not be garbage collected. See this question for details.
The main Thread of your program is always alive until the JVM shuts down.
Why are you asking this question ?
Every JVM instance has only one java.lang.Runtime instance. Created at the start and stays till the end. If you want everlasting then there are two ways:
Override protected void finalize() throws Throwable; and Self reference the object in it.
Maintain reference to your object
Of course. All you have to do is make sure the object is reachable by running code, and it won't die. The GC only collects stuff that the code doesn't have a reference to anymore.
A single static reference (that you never set to null) within one of your classes should be enough to guarantee that the object sticks around as long as the app is running. However, as long as you are able to see and use the object, it should stick around anyway. (There's a concept called "weak references" that makes this not always true, but if you're using them, then you wouldn't be asking the question.)