## 1 内存泄漏

内存泄漏是内存优化的重点，内存泄漏，简单来说，就是使用的对象没用释放掉。Android 中的内存泄漏主要包含以下三类：

* 程序员自己的编码造成的泄漏（可控）
* 第三方框架造成的泄漏（不可控）
* Android 系统或第三方 ROM 造成的泄漏（不可控）

## 2 内存泄漏的场景

### 2.1 非静态内部类的静态实例

非静态内部类会持有外部类实例的引用，如果非静态内部类的实例是静态的，就会长期持有外部类的引用。

### 2.2 多线程相关的匿名类/非静态内部类

匿名内部类会持有外部类实例的引用。 

### 2.3 Handler 内存泄漏

Handler 的 Message 被存储在 MessageQueue 中，当 Message 没有及时处理，或者延迟处理，会导致 MEssageQueue 存在的时间长，Handler 无法被回收，如果 Handler 是非静态，Handler 会持有外部 Activity 或 Service 不能被回收。

解决：

* 使用静态的 Handler

* 弱引用，或者 onDestory -> 移除 MessageQueue

  ```java
  private static class MyHandler extends Handler {
      private final WeakReference<xxxActivity> mActivity;
      public MyHandler() {
          mActivity = new WeakReference<>(xxxActivity);
      }
      public void handleMessage(Message msg) {
          if(mActivity !=null && mActivity.get() == null) {
              mActivity.get().show();
          }
      }
  } 
  ```

### 2.4 未正确使用 Context

对于不是必须使用 Activity 的 Context 的情况，可以使用 Application Context 来代替。

### 2.5 静态 View

使用静态的 View，会持有 Activity 的引用，导致 Activity 无法被回收。

### 2.6 WebView

在 Android 中使用一次 WebView ，内存不会被释放，可以开一个新进程，使用 AIDL 与应用的主进程进行通信。

### 2.7 资源对象未关闭

Cursor、File 等对象，往往使用缓冲，会造成内存泄漏，在资源对象未使用时，可以把引用置为 null。

### 2.8 集合中的对象没有清理

集合中的对象不使用，没有清理集合中的对象，不断往里面增加对象，导致集合会越来越大。

### 2.9 Bitmap 对象

加入创建了一个大的 Bitmap 对象，经过变换之后，等到一个新的 Bitmap，假如旧的 Bitmap 没有被回收，可能造成泄漏。

### 2.10 监听器未关闭

很多系统服务、广播、EventBud 等 注册之后没有反注册，可能会造成内存泄漏。

## 3 利用 Android Profiler 测量应用性能

Android Studio 3.0 及更高版本中的 Android Profiler 取代了 Android Monitor 工具。Android Profiler 工具可提供实时数据，帮助您了解应用的 CPU、内存、网络和电池资源使用情况，我们可以在 google 开发平台查看使用。

[Android Profiler](https://developer.android.google.cn/studio/profile/android-profiler)

[Android Profiler内存检测](https://www.cnblogs.com/zhaozhengwu/p/10578562.html)

## 4 使用 MAT 进行内存分析

准备测试代码

```java
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TestThread testThread = new TestThread();
        testThread.start();
    }

    class TestThread extends Thread{
        @Override
        public void run() {
            try {
                Thread.sleep(60*60*1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
```

具体使用重看这篇文章 [Android Profiler mat](https://blog.csdn.net/kongbaidepao/article/details/108011943)
