# 内存优化（LeakCanary原理）

## 概述

内存泄漏是Android开发中的常见问题，会导致应用内存占用持续增长，最终可能引发OOM（Out of Memory）崩溃。LeakCanary是Square公司开源的内存泄漏检测工具，本文档深入解析其工作原理和使用方法。

## 内存泄漏基础

### 什么是内存泄漏

内存泄漏是指程序在运行过程中，由于某些原因导致已分配的内存无法被回收，造成内存浪费和潜在的性能问题。

### Android中的内存泄漏场景

1. **静态变量持有Context**
```java
// 错误示例
public class MyApplication {
    private static Context sContext; // 持有Activity引用
}

// 正确做法
public class MyApplication {
    private static Context sAppContext; // 使用Application Context
}
```

2. **非静态内部类持有外部类引用**
```java
// 错误示例
public class MainActivity extends Activity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // 隐式持有MainActivity引用
        }
    };
}

// 正确做法：使用静态内部类 + WeakReference
public class MainActivity extends Activity {
    private static class MyHandler extends Handler {
        private WeakReference<MainActivity> mActivityRef;
        
        MyHandler(MainActivity activity) {
            mActivityRef = new WeakReference<>(activity);
        }
        
        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = mActivityRef.get();
            if (activity != null) {
                // 使用activity
            }
        }
    }
}
```

3. **监听器未注销**
```java
// 错误示例
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this); // 注册但未注销
    }
}

// 正确做法
@Override
protected void onDestroy() {
    super.onDestroy();
    EventBus.getDefault().unregister(this);
}
```

4. **资源未关闭**
```java
// 错误示例
FileInputStream fis = new FileInputStream(file);
// 使用后未关闭

// 正确做法：使用try-with-resources
try (FileInputStream fis = new FileInputStream(file)) {
    // 使用fis
} // 自动关闭
```

## LeakCanary工作原理

### 核心机制

LeakCanary通过以下步骤检测内存泄漏：

1. **对象引用监控**: 监控Activity/Fragment等关键对象的生命周期
2. **弱引用检测**: 使用WeakReference + ReferenceQueue检测对象是否被回收
3. **堆转储分析**: 当检测到泄漏时，dump堆内存进行分析
4. **泄漏路径分析**: 使用Shark库分析GC Root到泄漏对象的引用链

### 工作流程

```
Activity创建
    ↓
LeakCanary.watch() 监控
    ↓
Activity销毁
    ↓
等待5秒（GC时间）
    ↓
检查对象是否被回收
    ↓
未回收 → 触发堆转储
    ↓
分析引用链
    ↓
生成泄漏报告
```

### 源码关键点

#### 1. ObjectWatcher

```java
// 监控对象是否被回收
public class ObjectWatcher {
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
    private final Map<String, KeyedWeakReference> watchedObjects = new HashMap<>();
    
    public void watch(Object watchedObject, String referenceName) {
        KeyedWeakReference reference = new KeyedWeakReference(
            watchedObject, referenceName, queue, clock);
        watchedObjects.put(key, reference);
    }
}
```

#### 2. HeapDumper

```java
// 堆转储
public interface HeapDumper {
    File dumpHeap();
}
```

#### 3. HeapAnalyzer

```java
// 分析堆转储文件
public class HeapAnalyzer {
    public AnalysisResult checkForLeaks(File heapDumpFile) {
        // 使用Shark库分析hprof文件
        // 查找GC Root到泄漏对象的路径
    }
}
```

## LeakCanary集成

### 添加依赖

```gradle
dependencies {
    // LeakCanary
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
}
```

### 自动安装（无需代码）

LeakCanary 2.0+ 使用ContentProvider自动初始化，无需手动配置。

### 手动监控

```java
// 监控自定义对象
LeakCanary.INSTANCE.getObjectWatcher().watch(
    myObject, 
    "MyObject被监控"
);
```

## 常见内存泄漏案例

### 1. Handler泄漏

**问题代码**:
```java
public class MainActivity extends Activity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // Handler持有MainActivity的隐式引用
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 发送延迟消息
        mHandler.sendEmptyMessageDelayed(0, 60000);
    }
}
```

**解决方案**:
```java
public class MainActivity extends Activity {
    private static class MyHandler extends Handler {
        private WeakReference<MainActivity> mActivityRef;
        
        MyHandler(MainActivity activity) {
            mActivityRef = new WeakReference<>(activity);
        }
        
        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = mActivityRef.get();
            if (activity == null) {
                return;
            }
            // 处理消息
        }
    }
    
    private MyHandler mHandler = new MyHandler(this);
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }
}
```

### 2. 单例持有Context

**问题代码**:
```java
public class AppManager {
    private static AppManager sInstance;
    private Context mContext;
    
    private AppManager(Context context) {
        mContext = context; // 可能持有Activity
    }
    
    public static AppManager getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new AppManager(context);
        }
        return sInstance;
    }
}
```

**解决方案**:
```java
public class AppManager {
    private static AppManager sInstance;
    private Context mContext;
    
    private AppManager(Context context) {
        // 使用Application Context
        mContext = context.getApplicationContext();
    }
    
    public static AppManager getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new AppManager(context);
        }
        return sInstance;
    }
}
```

### 3. 匿名内部类

**问题代码**:
```java
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 匿名内部类持有外部类引用
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 长时间运行的任务
                while (true) {
                    // ...
                }
            }
        }).start();
    }
}
```

**解决方案**:
```java
public class MainActivity extends Activity {
    private static class MyRunnable implements Runnable {
        private WeakReference<MainActivity> mActivityRef;
        
        MyRunnable(MainActivity activity) {
            mActivityRef = new WeakReference<>(activity);
        }
        
        @Override
        public void run() {
            MainActivity activity = mActivityRef.get();
            if (activity == null) {
                return;
            }
            // 执行任务
        }
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new Thread(new MyRunnable(this)).start();
    }
}
```

## 内存优化最佳实践

### 1. 使用Application Context

```java
// 优先使用Application Context
Context appContext = context.getApplicationContext();
```

### 2. 及时释放资源

```java
@Override
protected void onDestroy() {
    super.onDestroy();
    // 注销监听器
    // 取消网络请求
    // 停止动画
    // 释放资源
}
```

### 3. 使用WeakReference

```java
// 对于可能持有Activity引用的对象，使用WeakReference
private WeakReference<Activity> mActivityRef;
```

### 4. 避免静态变量持有View/Context

```java
// 错误
private static TextView sTextView;

// 正确：使用WeakReference或避免静态变量
```

### 5. 使用对象池

```java
// 复用对象，减少GC压力
ObjectPool<MyObject> pool = new ObjectPool<>(10);
MyObject obj = pool.acquire();
// 使用后归还
pool.release(obj);
```

## 内存分析工具

### 1. Android Profiler

- 实时内存监控
- 堆转储分析
- 内存分配追踪

### 2. MAT (Memory Analyzer Tool)

- 分析hprof文件
- 查找内存泄漏
- 查看对象引用关系

### 3. LeakCanary

- 自动检测泄漏
- 可视化引用链
- 开发阶段使用

## 内存优化指标

- **峰值内存**: 根据设备配置设定上限（如512MB）
- **内存泄漏**: 0个
- **GC频率**: 尽量减少Full GC
- **内存抖动**: 避免频繁分配/释放

## 相关链接

- [[README]]
- [[09-调试与工具链]]
- [[05-进程与线程通信]]
