110 lines
5.5 KiB
Plaintext
110 lines
5.5 KiB
Plaintext
|
page.title=Avoiding Memory Leaks
|
||
|
@jd:body
|
||
|
|
||
|
|
||
|
<p>Android applications are, at least on the T-Mobile G1, limited
|
||
|
to 16 MB of heap. It's both a lot of memory for a phone and yet very
|
||
|
little for what some developers want to achieve. Even if you do not
|
||
|
plan on using all of this memory, you should use as little as possible
|
||
|
to let other applications run without getting them killed. The more
|
||
|
applications Android can keep in memory, the faster it will be for the
|
||
|
user to switch between his apps. As part of my job, I ran into memory
|
||
|
leaks issues in Android applications and they are most of the time due
|
||
|
to the same mistake: keeping a long-lived reference to a
|
||
|
{@link android.content.Context Context}.</p>
|
||
|
|
||
|
<p>On Android, a <code>Context</code> is used for many operations
|
||
|
but mostly to load and access resources. This is why all the widgets
|
||
|
receive a <code>Context</code> parameter in their constructor. In a
|
||
|
regular Android application, you usually have two kinds of
|
||
|
<code>Context</code>, {@link android.app.Activity} and
|
||
|
{@link android.app.Application}. It's usually the first one that
|
||
|
the developer passes to classes and methods that need a <code>Context</code>:</p>
|
||
|
|
||
|
<pre class="prettyprint">@Override
|
||
|
protected void onCreate(Bundle state) {
|
||
|
super.onCreate(state);
|
||
|
|
||
|
TextView label = new TextView(this);
|
||
|
label.setText("Leaks are bad");
|
||
|
|
||
|
setContentView(label);
|
||
|
}
|
||
|
</pre>
|
||
|
|
||
|
<p>This means 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. Therefore, if you leak the <code>Context</code>
|
||
|
("leak" meaning you keep a reference to it thus preventing the GC from
|
||
|
collecting it), you leak a lot of memory. Leaking an entire activity
|
||
|
can be really easy if you're not careful.</p>
|
||
|
|
||
|
<p>When the screen orientation changes the system will, by default,
|
||
|
destroy the current activity and create a new one while preserving its
|
||
|
state. In doing so, Android will reload the application's UI from the
|
||
|
resources. Now imagine you wrote an application with a large bitmap
|
||
|
that you don't want to load on every rotation. The easiest way to keep
|
||
|
it around and not having to reload it on every rotation is to keep in a
|
||
|
static field:</p>
|
||
|
|
||
|
<pre class="prettyprint">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);
|
||
|
}
|
||
|
</pre>
|
||
|
|
||
|
<p>This code is very fast and also very wrong; it leaks the first activity
|
||
|
created upon the first screen orientation change. When a
|
||
|
{@link android.graphics.drawable.Drawable Drawable} is attached to a view, the view is set as a
|
||
|
{@link android.graphics.drawable.Drawable#setCallback(android.graphics.drawable.Drawable.Callback) callback}
|
||
|
on the drawable. In the code snippet above, this means the drawable has a
|
||
|
reference to the <code>TextView</code> which itself has a reference to the
|
||
|
activity (the <code>Context</code>) which in turns has references to
|
||
|
pretty much anything (depending on your code.)</p>
|
||
|
|
||
|
<p>This example is one of the simplest cases of leaking the
|
||
|
<code>Context</code> and you can see how we worked around it in the
|
||
|
<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>
|
||
|
(look for the <code>unbindDrawables()</code> method) by setting the stored
|
||
|
drawables' callbacks to null when the activity is destroyed. Interestingly
|
||
|
enough, there are cases where you can create a chain of leaked contexts,
|
||
|
and they are bad. They make you run out of memory rather quickly.</p>
|
||
|
|
||
|
<p>There are two easy ways to avoid context-related memory leaks. The most
|
||
|
obvious one is to avoid escaping the context outside of its own scope. The
|
||
|
example above showed the case of a static reference but inner classes and
|
||
|
their implicit reference to the outer class can be equally dangerous. The
|
||
|
second solution is to use the <code>Application</code> context. This
|
||
|
context will live as long as your application is alive and does not depend
|
||
|
on the activities life cycle. If you plan on keeping long-lived objects
|
||
|
that need a context, remember the application object. You can obtain it
|
||
|
easily by calling
|
||
|
{@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
|
||
|
or {@link android.app.Activity#getApplication() Activity.getApplication()}.</p>
|
||
|
|
||
|
<p>In summary, to avoid context-related memory leaks, remember the following:</p>
|
||
|
<ul>
|
||
|
<li>Do not keep long-lived references to a context-activity (a reference
|
||
|
to an activity should have the same life cycle as the activity itself)</li>
|
||
|
<li>Try using the context-application instead of a context-activity</li>
|
||
|
<li>Avoid non-static inner classes in an activity if you don't control
|
||
|
their life cycle, use a static inner class and make a weak reference to
|
||
|
the activity inside. The solution to this issue is to use a static inner
|
||
|
class with a {@link java.lang.ref.WeakReference WeakReference} to the
|
||
|
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>
|
||
|
and its W inner class for instance</li>
|
||
|
<li>A garbage collector is not an insurance against memory leaks</li>
|
||
|
</ul>
|