# 内存优化

## 目录
- [内存泄漏](#内存泄漏)
- [内存抖动](#内存抖动)
- [内存分析工具](#内存分析工具)
- [内存优化方案](#内存优化方案)
- [图片内存优化](#图片内存优化)
- [对象池](#对象池)
- [面试常见问题](#面试常见问题)

---

## 内存泄漏

### 什么是内存泄漏？

内存泄漏是指程序在运行过程中，由于某些原因导致无法释放已经不再使用的内存，造成内存浪费，最终可能导致 OOM（OutOfMemoryError）。

### 常见内存泄漏场景

#### 1. 静态变量持有 Context

```java
// ❌ 错误示例
public class MyActivity extends AppCompatActivity {
    private static Context sContext;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sContext = this; // 静态变量持有 Activity，导致泄漏
    }
}

// ✅ 正确做法
public class MyActivity extends AppCompatActivity {
    private static Context sContext;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sContext = getApplicationContext(); // 使用 Application Context
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        sContext = null; // 及时释放
    }
}
```

#### 2. Handler 内存泄漏

```java
// ❌ 错误示例
public class MyActivity extends AppCompatActivity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // Handler 持有 Activity 的隐式引用
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                // 如果 Activity 已销毁，但 Handler 还在处理消息，导致泄漏
            }
        }, 10000);
    }
}

// ✅ 正确做法
public class MyActivity extends AppCompatActivity {
    private Handler mHandler;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mHandler = new Handler(Looper.getMainLooper()) {
            @Override
            public void handleMessage(Message msg) {
                if (MyActivity.this.isFinishing()) {
                    return; // Activity 已销毁，不处理消息
                }
                // 处理消息
            }
        };
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null); // 移除所有消息
    }
}

// ✅ 使用静态内部类 + WeakReference
public class MyActivity extends AppCompatActivity {
    private static class MyHandler extends Handler {
        private WeakReference<MyActivity> mActivity;
        
        MyHandler(MyActivity activity) {
            mActivity = new WeakReference<>(activity);
        }
        
        @Override
        public void handleMessage(Message msg) {
            MyActivity activity = mActivity.get();
            if (activity == null || activity.isFinishing()) {
                return;
            }
            // 处理消息
        }
    }
}
```

#### 3. 单例模式持有 Context

```java
// ❌ 错误示例
public class Singleton {
    private static Singleton instance;
    private Context mContext;
    
    private Singleton(Context context) {
        this.mContext = context; // 持有 Activity Context
    }
    
    public static Singleton getInstance(Context context) {
        if (instance == null) {
            instance = new Singleton(context);
        }
        return instance;
    }
}

// ✅ 正确做法
public class Singleton {
    private static Singleton instance;
    private Context mContext;
    
    private Singleton(Context context) {
        this.mContext = context.getApplicationContext(); // 使用 Application Context
    }
    
    public static Singleton getInstance(Context context) {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton(context);
                }
            }
        }
        return instance;
    }
}
```

#### 4. 内部类持有外部类引用

```java
// ❌ 错误示例
public class MyActivity extends AppCompatActivity {
    private MyAsyncTask mTask;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mTask = new MyAsyncTask(); // 内部类持有 Activity 引用
        mTask.execute();
    }
    
    private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            // 耗时操作
            return null;
        }
    }
}

// ✅ 正确做法：使用静态内部类
public class MyActivity extends AppCompatActivity {
    private MyAsyncTask mTask;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mTask = new MyAsyncTask(this);
        mTask.execute();
    }
    
    private static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        private WeakReference<MyActivity> mActivity;
        
        MyAsyncTask(MyActivity activity) {
            mActivity = new WeakReference<>(activity);
        }
        
        @Override
        protected Void doInBackground(Void... voids) {
            // 耗时操作
            return null;
        }
        
        @Override
        protected void onPostExecute(Void aVoid) {
            MyActivity activity = mActivity.get();
            if (activity == null || activity.isFinishing()) {
                return;
            }
            // 更新 UI
        }
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mTask != null) {
            mTask.cancel(true);
        }
    }
}
```

#### 5. 监听器未注销

```java
// ❌ 错误示例
public class MyActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
        // 忘记注销监听器
    }
}

// ✅ 正确做法
public class MyActivity extends AppCompatActivity {
    private SensorManager mSensorManager;
    private Sensor mSensor;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mSensorManager != null) {
            mSensorManager.unregisterListener(this); // 注销监听器
        }
    }
}
```

#### 6. 集合类持有对象引用

```java
// ❌ 错误示例
public class MyActivity extends AppCompatActivity {
    private static List<View> sViews = new ArrayList<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = findViewById(R.id.view);
        sViews.add(view); // 静态集合持有 View，View 持有 Activity，导致泄漏
    }
}

// ✅ 正确做法
public class MyActivity extends AppCompatActivity {
    private static List<WeakReference<View>> sViews = new ArrayList<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = findViewById(R.id.view);
        sViews.add(new WeakReference<>(view));
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 清理集合
        sViews.clear();
    }
}
```

---

## 内存抖动

### 什么是内存抖动？

内存抖动是指短时间内频繁分配和回收内存，导致 GC 频繁执行，影响应用性能。

### 内存抖动的原因

1. **频繁创建对象**：在循环中创建大量临时对象
2. **字符串拼接**：使用 `+` 拼接字符串
3. **集合扩容**：集合频繁扩容导致内存分配

### 内存抖动示例

```java
// ❌ 错误示例：频繁创建对象
for (int i = 0; i < 10000; i++) {
    String str = new String("Hello" + i); // 每次循环都创建新对象
    list.add(str);
}

// ✅ 正确做法：使用 StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
    sb.append("Hello").append(i);
    list.add(sb.toString());
    sb.setLength(0); // 清空 StringBuilder
}

// ❌ 错误示例：字符串拼接
String result = "";
for (int i = 0; i < 1000; i++) {
    result += "item" + i; // 每次拼接都创建新对象
}

// ✅ 正确做法：使用 StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append("item").append(i);
}
String result = sb.toString();
```

---

## 内存分析工具

### 1. LeakCanary

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

#### 使用
```java
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        if (LeakCanary.isInAnalyzerProcess(this)) {
            return;
        }
        LeakCanary.install(this);
    }
}
```

### 2. Android Studio Memory Profiler

- 实时查看内存使用
- 查看内存分配
- 查看内存泄漏
- 生成 Heap Dump

### 3. MAT (Memory Analyzer Tool)

- 分析 Heap Dump
- 查找内存泄漏
- 查看对象引用关系

### 4. adb 命令

```bash
# 查看内存信息
adb shell dumpsys meminfo <package_name>

# 查看进程内存
adb shell dumpsys meminfo <pid>

# 强制 GC
adb shell am force-stop <package_name>
```

---

## 内存优化方案

### 1. 使用对象池

```java
public class ObjectPool<T> {
    private Queue<T> pool = new LinkedList<>();
    private Supplier<T> factory;
    private int maxSize;
    
    public ObjectPool(Supplier<T> factory, int maxSize) {
        this.factory = factory;
        this.maxSize = maxSize;
    }
    
    public T acquire() {
        T obj = pool.poll();
        if (obj == null) {
            obj = factory.get();
        }
        return obj;
    }
    
    public void release(T obj) {
        if (pool.size() < maxSize) {
            pool.offer(obj);
        }
    }
}

// 使用
ObjectPool<StringBuilder> pool = new ObjectPool<>(
    StringBuilder::new, 10
);
StringBuilder sb = pool.acquire();
// 使用 sb
pool.release(sb);
```

### 2. 使用弱引用

```java
// WeakReference：GC 时会被回收
WeakReference<Activity> weakRef = new WeakReference<>(activity);
Activity activity = weakRef.get();
if (activity == null) {
    // 已被回收
}

// SoftReference：内存不足时会被回收
SoftReference<Bitmap> softRef = new SoftReference<>(bitmap);
Bitmap bitmap = softRef.get();
if (bitmap == null) {
    // 已被回收
}
```

### 3. 及时释放资源

```java
public class MyActivity extends AppCompatActivity {
    private Bitmap mBitmap;
    private FileInputStream mInputStream;
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        
        // 释放 Bitmap
        if (mBitmap != null && !mBitmap.isRecycled()) {
            mBitmap.recycle();
            mBitmap = null;
        }
        
        // 关闭流
        if (mInputStream != null) {
            try {
                mInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mInputStream = null;
        }
    }
}
```

### 4. 使用 SparseArray 替代 HashMap

```java
// HashMap<Integer, Object> 会创建 Integer 对象
HashMap<Integer, String> map = new HashMap<>();

// SparseArray 避免自动装箱
SparseArray<String> sparseArray = new SparseArray<>();
sparseArray.put(1, "value");
```

### 5. 避免在 onDraw 中创建对象

```java
// ❌ 错误示例
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint paint = new Paint(); // 每次绘制都创建新对象
    canvas.drawText("Hello", 0, 0, paint);
}

// ✅ 正确做法
public class MyView extends View {
    private Paint mPaint; // 复用 Paint 对象
    
    public MyView(Context context) {
        super(context);
        mPaint = new Paint();
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText("Hello", 0, 0, mPaint);
    }
}
```

---

## 图片内存优化

### 1. 图片压缩

```java
public Bitmap compressBitmap(Bitmap bitmap, int maxWidth, int maxHeight) {
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    
    float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
    if (scale < 1.0f) {
        int newWidth = Math.round(width * scale);
        int newHeight = Math.round(height * scale);
        return Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
    }
    return bitmap;
}
```

### 2. 使用合适的图片格式

- **WebP**：压缩率高，支持透明
- **PNG**：无损压缩，适合图标
- **JPEG**：有损压缩，适合照片

### 3. 使用 inSampleSize

```java
public Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    int height = options.outHeight;
    int width = options.outWidth;
    int inSampleSize = 1;
    
    if (height > reqHeight || width > reqWidth) {
        int halfHeight = height / 2;
        int halfWidth = width / 2;
        while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
            inSampleSize *= 2;
        }
    }
    return inSampleSize;
}
```

### 4. 使用 RGB_565

```java
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565; // 减少内存占用
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image, options);
```

### 5. 及时回收 Bitmap

```java
if (bitmap != null && !bitmap.isRecycled()) {
    bitmap.recycle();
    bitmap = null;
}
```

---

## 对象池

### 实现对象池

```java
public class RecyclerPool<T> {
    private final Queue<T> pool = new LinkedList<>();
    private final Supplier<T> factory;
    private final Consumer<T> reset;
    private final int maxSize;
    
    public RecyclerPool(Supplier<T> factory, Consumer<T> reset, int maxSize) {
        this.factory = factory;
        this.reset = reset;
        this.maxSize = maxSize;
    }
    
    public T acquire() {
        T obj = pool.poll();
        if (obj == null) {
            obj = factory.get();
        }
        return obj;
    }
    
    public void release(T obj) {
        if (obj == null) {
            return;
        }
        reset.accept(obj);
        if (pool.size() < maxSize) {
            pool.offer(obj);
        }
    }
    
    public void clear() {
        pool.clear();
    }
}

// 使用示例
RecyclerPool<StringBuilder> pool = new RecyclerPool<>(
    StringBuilder::new,
    sb -> sb.setLength(0),
    10
);

StringBuilder sb = pool.acquire();
sb.append("Hello");
// 使用完毕
pool.release(sb);
```

---

## 面试常见问题

### Q1: 什么是内存泄漏？如何避免？

**答案：**
- 内存泄漏是指程序无法释放不再使用的内存
- 常见原因：静态变量持有 Context、Handler 未移除消息、监听器未注销等
- 避免方法：使用 Application Context、使用 WeakReference、及时注销监听器等

### Q2: Handler 为什么会导致内存泄漏？

**答案：**
- Handler 持有 Activity 的隐式引用
- Message 持有 Handler 的引用
- MessageQueue 持有 Message 的引用
- 如果 Handler 还有未处理的消息，Activity 就无法被回收

### Q3: 如何检测内存泄漏？

**答案：**
1. 使用 LeakCanary 自动检测
2. 使用 Android Studio Memory Profiler
3. 使用 MAT 分析 Heap Dump
4. 使用 adb dumpsys meminfo 命令

### Q4: 什么是内存抖动？如何避免？

**答案：**
- 内存抖动是短时间内频繁分配和回收内存
- 避免方法：使用对象池、使用 StringBuilder、避免在循环中创建对象

### Q5: 如何优化图片内存？

**答案：**
1. 使用合适的图片格式（WebP、PNG、JPEG）
2. 使用 inSampleSize 压缩
3. 使用 RGB_565 减少内存
4. 及时回收 Bitmap
5. 使用图片加载库（Glide、Picasso）

### Q6: Context 的使用注意事项？

**答案：**
- Activity Context：生命周期短，不能长期持有
- Application Context：生命周期长，可以长期持有
- 静态变量、单例等应使用 Application Context

### Q7: 如何优化内存使用？

**答案：**
1. 避免内存泄漏
2. 使用对象池复用对象
3. 使用弱引用
4. 及时释放资源
5. 优化图片内存
6. 使用 SparseArray 替代 HashMap

---

## 总结

内存优化是 Android 性能优化的重要部分，主要从以下几个方面入手：

1. **避免内存泄漏**：注意 Context、Handler、监听器的使用
2. **避免内存抖动**：减少对象创建，使用对象池
3. **优化图片内存**：压缩、使用合适格式、及时回收
4. **使用工具检测**：LeakCanary、Memory Profiler、MAT

通过合理的内存优化，可以避免 OOM，提升应用性能。

---

*最后更新：2024年*
