Home | History | Annotate | Download | only in articles
      1 page.title=Avoiding Memory Leaks
      2 parent.title=Articles
      3 parent.link=../browser.html?tag=article
      4 @jd:body
      5 
      6 
      7 <p>Android applications are, at least on the T-Mobile G1, limited
      8 to 16 MB of heap. It's both a lot of memory for a phone and yet very
      9 little for what some developers want to achieve. Even if you do not
     10 plan on using all of this memory, you should use as little as possible
     11 to let other applications run without getting them killed. The more
     12 applications Android can keep in memory, the faster it will be for the
     13 user to switch between his apps. As part of my job, I ran into memory
     14 leaks issues in Android applications and they are most of the time due
     15 to the same mistake: keeping a long-lived reference to a 
     16 {@link android.content.Context Context}.</p>
     17 
     18 <p>On Android, a <code>Context</code> is used for many operations
     19  but mostly to load and access resources. This is why all the widgets 
     20 receive a <code>Context</code> parameter in their constructor. In a 
     21 regular Android application, you usually have two kinds of 
     22 <code>Context</code>, {@link android.app.Activity} and 
     23 {@link android.app.Application}. It's usually the first one that 
     24 the developer passes to classes and methods that need a <code>Context</code>:</p>
     25 
     26 <pre class="prettyprint">&#64;Override
     27 protected void onCreate(Bundle state) {
     28   super.onCreate(state);
     29   
     30   TextView label = new TextView(this);
     31   label.setText("Leaks are bad");
     32   
     33   setContentView(label);
     34 }
     35 </pre>
     36 
     37 <p>This means that views have a reference to the entire activity and
     38 therefore to anything your activity is holding onto; usually the entire
     39 View hierarchy and all its resources. Therefore, if you leak the <code>Context</code>
     40 ("leak" meaning you keep a reference to it thus preventing the GC from
     41 collecting it), you leak a lot of memory. Leaking an entire activity
     42 can be really easy if you're not careful.</p>
     43 
     44 <p>When the screen orientation changes the system will, by default,
     45 destroy the current activity and create a new one while preserving its
     46 state. In doing so, Android will reload the application's UI from the
     47 resources. Now imagine you wrote an application with a large bitmap
     48 that you don't want to load on every rotation. The easiest way to keep
     49 it around and not having to reload it on every rotation is to keep in a
     50 static field:</p>
     51 
     52 <pre class="prettyprint">private static Drawable sBackground;
     53   
     54 &#64;Override
     55 protected void onCreate(Bundle state) {
     56   super.onCreate(state);
     57   
     58   TextView label = new TextView(this);
     59   label.setText("Leaks are bad");
     60   
     61   if (sBackground == null) {
     62     sBackground = getDrawable(R.drawable.large_bitmap);
     63   }
     64   label.setBackgroundDrawable(sBackground);
     65   
     66   setContentView(label);
     67 }
     68 </pre> 
     69 
     70 <p>This code is very fast and also very wrong; it leaks the first activity 
     71 created upon the first screen orientation change. When a 
     72 {@link android.graphics.drawable.Drawable Drawable} is attached to a view, the view is set as a 
     73 {@link android.graphics.drawable.Drawable#setCallback(android.graphics.drawable.Drawable.Callback) callback} 
     74 on the drawable. In the code snippet above, this means the drawable has a 
     75 reference to the <code>TextView</code> which itself has a reference to the 
     76 activity (the <code>Context</code>) which in turns has references to 
     77 pretty much anything (depending on your code.)</p> 
     78  
     79 <p>This example is one of the simplest cases of leaking the 
     80 <code>Context</code> and you can see how we worked around it in the 
     81 <a href="http://android.git.kernel.org/?p=platform/packages/apps/Launcher.git;a=blob;f=src/com/android/launcher/LauncherModel.java;h=0ef2a806b767142b28b2ff3b37f21f4ca16c355d;hb=cupcake">Home screen's source code</a>
     82 (look for the <code>unbindDrawables()</code> method) by setting the stored 
     83 drawables' callbacks to null when the activity is destroyed. Interestingly 
     84 enough, there are cases where you can create a chain of leaked contexts, 
     85 and they are bad. They make you run out of memory rather quickly.</p> 
     86  
     87 <p>There are two easy ways to avoid context-related memory leaks. The most 
     88 obvious one is to avoid escaping the context outside of its own scope. The 
     89 example above showed the case of a static reference but inner classes and 
     90 their implicit reference to the outer class can be equally dangerous. The 
     91 second solution is to use the <code>Application</code> context. This 
     92 context will live as long as your application is alive and does not depend 
     93 on the activities life cycle. If you plan on keeping long-lived objects 
     94 that need a context, remember the application object. You can obtain it 
     95 easily by calling 
     96 {@link android.content.Context#getApplicationContext() Context.getApplicationContext()} 
     97 or {@link android.app.Activity#getApplication() Activity.getApplication()}.</p> 
     98  
     99 <p>In summary, to avoid context-related memory leaks, remember the following:</p> 
    100 <ul> 
    101 <li>Do not keep long-lived references to a context-activity (a reference 
    102 to an activity should have the same life cycle as the activity itself)</li> 
    103 <li>Try using the context-application instead of a context-activity</li> 
    104 <li>Avoid non-static inner classes in an activity if you don't control 
    105 their life cycle, use a static inner class and make a weak reference to 
    106 the activity inside. The solution to this issue is to use a static inner 
    107 class with a {@link java.lang.ref.WeakReference WeakReference} to the 
    108 outer class, as done in <a href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/view/ViewRoot.java;h=9d7a124cb01ab94bf53e34f6e5e8a07f81e2423c;hb=master">ViewRoot</a>
    109 and its W inner class for instance</li> 
    110 <li>A garbage collector is not an insurance against memory leaks</li> 
    111 </ul> 
    112