Question

I am pretty newbie for android development and I just read Romain Guy's "Avoid memory leaks on Android" from the following link

http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/

Then I did a little test by his famous code snippet on my android emulator

private static Drawable drawable;

private StringBuilder sb;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    TextView label = new TextView(this);
    label.setText("Leaks are bad");

    if (drawable == null) {
        drawable = getResources().getDrawable(R.drawable.ic_launcher);
    }

    sb = new StringBuilder();

    for (int i = 0; i < 1024; i++) {
        sb.append('a');
    }

    label.setCompoundDrawables(null, drawable, null, null);

    setContentView(label);
}

This code is supposed to leak the first activity context while changing orientation. So I ran the program in emulator and change the orientation once (I also printed out 2 activity context ca.welcomelm.leaktest.MainActivity@45f81f98 and ca.welcomelm.leaktest.MainActivity@45f8d6f8 ). Then I dump the HPROF and jump to list objects by incoming reference char[]. I though I am supposed to see 2 char[] with the pattern "aaaaaaaaaaaa...", which are referenced by those 2 activity context. But I swear I only saw one referenced by the second context. The leaked context is not there. I think it is GCed. Can anyone else confirm this? Thanks

No correct solution

OTHER TIPS

Change:

if (drawable == null) {
        drawable = getResources().getDrawable(R.drawable.ic_launcher);
}

To something like:

if (drawable == null)
        drawable = getResources().getDrawable(R.drawable.ic_launcher);
else
        Log.i("blablabla", "Drawable initialized in prior activity");

And then start doing the screen rotations. You'll notice that Log.i will kick-in because the drawable is marked as static and is initialized already in prior activity. This is the point where memory leaks start to begin.

Since modern devices are pretty much hefty with memory resources thus you do not notice such leaks so easily. However, if your application contains a lot of such references or running over a low-end device then you may get lucky to head memory-leaks soon enough.

You are correct, the original TextView and the objects it referenced (Context, Activity, and more) will be GC'ed once the drawable releases the reference to the TextView. The release occurs when label.setCompoundDrawables() (in @user3375547's example) or label.setBackgroundDrawable() (in Romain Guy's original example) is called.

However, the Context was leaked for a time because the Drawable kept a reference to the TextView too long, preventing the previous Context (and all other referenced objects) from being GC'ed when they could have been.

Now, imagine a situation where Android did not create another instance of the Activity. For example, the user backs out of Activity. Android may destroy the Activity at this point. In this case the static reference still exists and keeps the Context from being GC'ed, causing a leak. The GC will only happen when the Activity is recreated, the application process is terminated, or the Classloader is GC'ed as @uDevel mentions in the comments below.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top