So I did tons of research regarding memory leaks in android and have read many StackOverflow posts. What I still don't understand is that according to Medium and StackOverflow posts (links mentioned below), If I pass my activity's context to an adaptor for Recyclerview and store it as a global variable in the adaptor, my activity along with the adaptor is still eligible for garbage collection. This is explained due to the fact that no GC roots have a reference to the adaptor or my activity (once it's destroyed) and so both will be garbage collected (Example1). However, why isn't the same case applied for inner classes? I get that they hold an implicit reference to their holding class, but if the activity (holding class in this case) gets destroyed and even if inner class is still executing some Async Task, shouldn't there be no GC roots pointing to any of them? (holding or the inner class) so both of them should get Garbage Collected? (Example 2).
Example1: (eligible for GC after activity gets destroyed):
public class MyAdaptor extends RecyclerView.Adaptor<>{
public Context context;
public MyAdaptor(Context context){
this.context=context;
}
}
public MyActivity extends AppCompatActivity {
private MyAdaptor myAdaptor;
@Override
protected void onCreate(Bundle savedInstanceState) {
//some code
myAdaptor=new MyAdaptor(this);
}
}
Example 2: (not eligible for GC after activity gets destroyed):
public MyHoldingActivity extends AppCompatActivity {
private MyInnerClass myInnerClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
myInnerClass=new MyInnerClass();
}
class MyInnerClass{
//executing some long Async Task
}
}
Links for both of the post I mentioned are mentioned below: https://medium.com/@oznusem/circular-dependency-in-android-should-i-worry-about-it-814660ac79ec
Is it leak-safe to keep a Context/Activity instance in RecyclerView.Adapter?
Sorry If I didn't make my question clear, this is my first post on StackOverflow.
Assuming that the AsyncTask
has a reference to your inner class, then:
If an inner class of an Activity
is running an AsyncTask
, even if the Activity
is finished, the GC will not be able to reclaim the Activity
because the inner class has a reference to the Activity
and the AsyncTask
has a reference to the inner class and Android's internal thread manager has a reference to the AsyncTask
. However, once the AsyncTask
completes, the GC can reclaim the Activity
since the internal thread manager will no longer have a reference to the AsyncTask
.
This isn't really a memory leak, as it is only a temporary situation. The Activity
will eventually be reclaimed. Real "memory leaks" occur when an object can never be reclaimed by the GC. Eventually such memory leaks can consume all available memory and cause a long-running application to crash with an OutOfMemoryException
.
You can prevent this by cancelling your AsyncTask
inside onDestroy()
of the Activity
.
Hopefully this answers your question.