Android中Handler导致的内存泄露
2015-01-29 08:00
399 查看
http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html
Consider the following code:
While not readily obvious, this code can cause cause a massive memory leak. Android Lint will give the following warning:
In Android, Handler classes should be static or leaks might occur.
But where exactly is the leak and how might it happen? Let's determine the source of the problem by first documenting what we know:
When an Android application first starts, the framework creates a
When a
In Java, non-static inner and anonymous classes hold an implicit reference to their outer class. Static inner classes, on the other hand, do not.
So where exactly is the memory leak? It's very subtle, but consider the following code as an example:
When the activity is finished, the delayed message will continue to live in the main thread's message queue for 10 minutes before it is processed. The message holds a reference to the activity's
To fix the problem, subclass the
The difference between static and non-static inner classes is subtle, but is something every Android developer should understand. What's the bottom line? Avoid using non-static inner classes in an activity if instances of the inner class could outlive the activity's lifecycle. Instead, prefer static inner classes and hold a weak reference to the activity inside.
Consider the following code:
1 2 3 4 5 6 7 8 9 | public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } } |
In Android, Handler classes should be static or leaks might occur.
But where exactly is the leak and how might it happen? Let's determine the source of the problem by first documenting what we know:
When an Android application first starts, the framework creates a
Looperobject for the application's main thread. A
Looperimplements a simple message queue, processing
Messageobjects in a loop one after another. All major application framework events (such as Activity lifecycle method calls, button clicks, etc.) are contained inside
Messageobjects, which are added to the
Looper's message queue and are processed one-by-one. The main thread's
Looperexists throughout the application's lifecycle.
When a
Handleris instantiated on the main thread, it is associated with the
Looper's message queue. Messages posted to the message queue will hold a reference to the
Handlerso that the framework can call
Handler#handleMessage(Message)when the
Loopereventually processes the message.
In Java, non-static inner and anonymous classes hold an implicit reference to their outer class. Static inner classes, on the other hand, do not.
So where exactly is the memory leak? It's very subtle, but consider the following code as an example:
1 2 3 4 5 6 7 8 9 | public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mLeakyHandler.postDelayed(new Runnable() { @Override public void run() { /* ... */ } }, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } } |
Handler, and the
Handlerholds an implicit reference to its outer class (the
SampleActivity, in this case). This reference will persist until the message is processed, thus preventing the activity context from being garbage collected and leaking all of the application's resources. Note that the same is true with the anonymous Runnable class on line 15. Non-static instances of anonymous classes hold an implicit reference to their outer class, so the context will be leaked.
To fix the problem, subclass the
Handlerin a new file or use a static inner class instead. Static inner classes do not hold an implicit reference to their outer class, so the activity will not be leaked. If you need to invoke the outer activity's methods from within the
Handler, have the Handler hold a
WeakReferenceto the activity so you don't accidentally leak a context. To fix the memory leak that occurs when we instantiate the anonymous Runnable class, we make the variable a static field of the class (since static instances of anonymous classes do not hold an implicit reference to their outer class):
1 2 3 4 5 6 7 8 9 | public class SampleActivity extends Activity { /** * Instances of static inner classes do not hold an implicit * reference to their outer class. */ private static class MyHandler extends Handler { private final WeakReference<SampleActivity> mActivity; public MyHandler(SampleActivity activity) { mActivity = new WeakReference<SampleActivity>(activity); } @Override public void handleMessage(Message msg) { SampleActivity activity = mActivity.get(); if (activity != null) { // ... } } } private final MyHandler mHandler = new MyHandler(this); /** * Instances of anonymous classes do not hold an implicit * reference to their outer class when they are "static". */ private static final Runnable sRunnable = new Runnable() { @Override public void run() { /* ... */ } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Post a message and delay its execution for 10 minutes. mHandler.postDelayed(sRunnable, 1000 * 60 * 10); // Go back to the previous Activity. finish(); } } |
相关文章推荐
- Android内存溢出与优化(四)——防止Handler导致的内存泄露
- Android中Handler使用不当导致内存泄露的问题
- Android:Handler,内部类导致的可能内存泄露
- Android Handler当做内部类,导致内存泄露的问题解决方案
- Android 中 Handler 引起的内存泄露 在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用。其实这可能导致内存泄露,代码中哪里可能导致内存泄露,又是如何
- Android中使用Handler造成内存泄露的分析和解决
- handler为activity的成员变量导致的内存泄露
- Android 中 Handler 引起的内存泄露
- Android中Handler引起的内存泄露
- Android中使用Handler造成内存泄露的分析和解决
- android中handler使用WeakReference防止内存泄露
- Android中Handler引起的内存泄露
- Handler导致内存泄露分析
- Android中使用Handler造成内存泄露的分析和解决
- handler为activity的成员变量导致的内存泄露
- android 内存泄露那些事情之Handler(一)
- Android App 内存泄露之Handler
- Android中使用Handler造成内存泄露的分析和解决
- 【android】Handler引起的内存泄露及解决办法
- Android-Fragment中TextView.setFocusable(true)导致的内存泄露