Andriod-内存泄露-分析-解决方案

来源:互联网 发布:java工程师是什么意思 编辑:程序博客网 时间:2024/06/05 19:00

Activity 泄漏 

我们第一个需要修复的问题就是 Activity 泄漏,我们先来看看内存泄漏是怎么发生的。 Activity 泄漏通常是内存泄漏的一种。为什么会泄漏呢?如果你持有一个未使用的 Activity 的引用,其实也就持有了 Activity 的布局,自然也就包含了所有的 View。最棘手的是持有静态引用。别忘了,Activity 和 Fragment 都有自己的生命周期。一旦我们持有了静态引用,Activity 和 Fragment 就不会被垃圾回收器清理掉了。这就是为什么静态引用很危险。

m_staticActivity = staticFragment.getActivity()

我看过太多次这样的代码了。

另外,泄漏 Listener 也是经常会发生的事情。比如说,我有下面的代码。LeakActivity继承自Activity,我们有一个单例:NastyManager,当我们通过 addListener(this) 将 Activity 作为 Listener 和 NastyManager 绑定起来的时候,不好的事情就发生了。

public class LeakActivity extends Activity {  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    NastyManager.getInstance().addListener(this);  }}

想要修复这样的 Bug,其实相当简单,就是在你的 Acitivity 被销毁的时候,将他和 NastyManager取消掉绑定就好了。

@Overridepublic void onDestroy() {  super.onDestroy();  NastyManager.getInstance().removeListener(this);}

相对上面的解决方案,我们自然还有更好的。比如我们真的需要用到单例吗?通常,并不需要。不过某些时候可能真的很需要。我们得权衡和设计。不过无论如何,记住,当 Activity 销毁的时候,在单例中移除掉对 Activity 的引用。下面我们讨论下: 如果是内部类,会发生什么?比如说,我们有一个在 Activity 里有一个很简短的非静态 Handler。

尽管它看起来很短,但是只要它还存活着,那么包含它的 Activity 就会存活着。如果你不信我,在 VM 里试试看。这就是另一个内存泄漏的案例:Activity 内部的 Handler

public class MainActivity extends Activity {  //...  Handler handler;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    //...    handler = new Handler() {      @Override      public void handleMessage(Message msg) {              }  }}

Handler 是个很常用也很有用的类,异步,线程安全等等。如果有下面这样的代码,会发生什么呢?handler.postDeslayed ,假设 delay 时间是几个小时… 这意味着什么?意味着只要 handler 的消息还没有被处理结束,它就一直存活着,包含它的 Activity 就跟着活着。我们来想办法修复它,修复的方案是WeakReference,也就是所谓的弱引用。垃圾回收器在回收的时候,是会忽视掉弱引用的,所以包含它的 Activity 会被正常清理掉。大概代码如下:

private static class MyHandler extends Handler {   private final WeakReference<MainActivity> mActivity;   // ...  public MyHandler(MainActivity activity) {    mActivity = new WeakReference<MainActivity>(activity);    //...   }  @Override  public void handleMessage(Message msg) {   }  //...}

 概括来说:我们有个内部类,就像 Handler,内部非静态类是不能脱离所属类而单独存活的,Android 里通常是   Activity。所以,看看你的代码里的内部类,确保他们没有出现内存泄漏。

  相比非静态内部类,最好使用静态内部类。区别就是静态内部类不依赖所属类,他们拥有不同的生命周期。我经常   见到类似的原因引起的内存泄露。

  如何避免 Activity 泄漏? 

  • 移除掉所有的静态引用。

  • 考虑用 EventBus 来解耦 Listener。

  • 记着在不需要的时候,解除 Listener 的绑定。

  • 尽量用静态内部类。

  • 做 Code Review。个人经验:Code Review 能很早的发现内存泄漏。

  • 了解你程序的结构。

  • 用类似 MAT,Eclipse Analyzer,LeakCanary 这样的工具分析内存。

  • 在 Callback 里打印 Log。

1 0
原创粉丝点击