According to Romain Guy this kind of code is prone to memory leak due to the fact that
.... views have a reference to the entire activity and therefore to anything your activity is holding onto; usually the entire View hierarchy and all its resources.
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
}
I am not clear about this.
Assuming an application with 1 activity, this is the longest lived object and can be recreated as needed. Which means that all of its instance fields (which can and usually are View
s) can be null at any time.
And any static instance field will live for the same duration as the activity itself.
So how can we get a memory leak with code like the above or the following:
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
Assuming an application with 1 activity, this is the longest lived object
No, it is not. There are other objects in your process (e.g., Application
, content providers) that will outlive an activity instance.
In particular, note that activities get destroyed and recreated by default on a configuration change (e.g., screen rotation).
And any static instance field will live for the same duration as the activity itself.
No. Static fields are around as long as the process is around. Your activity instances can be shorter-lived than that.
So how can we get a memory leak with code like the above or the following:
There is no static field in your first example.
Romain Guy explains the second scenario in the blog post that you linked to:
This code is very fast and also very wrong; it leaks the first activity created upon the first screen orientation change. When a Drawable is attached to a view, the view is set as a callback on the drawable. In the code snippet above, this means the drawable has a reference to the TextView which itself has a reference to the activity (the Context) which in turns has references to pretty much anything (depending on your code.)
And, if you added LeakCanary to your project, you would see the leak.
So, let's walk through this:
onCreate()
sBackground
is null
, and so you assign it the getDrawable()
resultonCreate()
sBackground
is not null
, and so you leave sBackground
aloneAnd you have your leak. As Romain explained, sBackground
has a not-very-obvious reference back to your original activity instance. So, now you have two outstanding instances of this activity: the leaked original, plus the new one created due to the configuration change.
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