Android 之 OOM的产生和解决办法
内存泄漏(Memory Leak)
原因:对象因错误引用(如静态变量、未注销监听器、Handler 消息未清理)无法被垃圾回收(GC),导致内存持续占用
。典型场景:
静态变量持有
Activity
引用。Handler
发送延迟消息后未移除,导致Activity
无法回收。未反注册
BroadcastReceiver
或传感器监听。
大对象滥用
原因:
图片处理不当:加载未压缩的高分辨率
Bitmap
(如 4K 图片占用 48MB 内存)。频繁创建对象:循环中拼接字符串或创建临时集合,引发内存抖动。
资源未释放
原因:未关闭
Cursor
、文件流、MediaPlayer
等,占用系统资源(如文件描述符耗尽)。
线程过多
原因:无限制创建线程,超出系统限制(如低端设备线程数上限 500)。
🛠️ 解决方案
1. 根治内存泄漏
避免强引用:用
WeakReference
替代静态变量持有Activity
。及时清理:在
onDestroy()
中移除Handler
消息、反注册监听器。工具检测:集成
LeakCanary
自动捕获泄漏链。
2. 优化图片处理
压缩采样:使用
BitmapFactory.Options.inSampleSize
按需缩放图片。低内存配置:设置
inPreferredConfig=RGB_565
(内存减半)。复用与回收:
通过
inBitmap
复用Bitmap
内存。调用
bitmap.recycle()
及时释放。
推荐库:
Glide
/Picasso
自动管理图片生命周期。
3. 控制内存占用
缓存策略:使用
LruCache
限制内存缓存大小(如堆内存的 1/8)。对象池:复用频繁创建的对象(如
Message
、自定义模型)。数据结构优化:
SparseArray
替代HashMap<Integer, Object>
。分块处理大数组(如 1MB/块)。
4. 释放资源与线程管理
关闭资源:在
finally
块中关闭流、Cursor
。线程池:用
ThreadPoolExecutor
限制并发线程数,避免无限创建。
5. 架构级优化
多进程拆分:将内存密集型模块(如相册、WebView)放入独立进程。
响应内存紧张:在
onTrimMemory()
中释放非关键缓存。
💎 总结
OOM 的核心矛盾是 有限内存 vs 无限需求。
优先解决内存泄漏(占 OOM 的 70%),辅以图片优化、资源释放。
预防>修复:开发阶段启用
StrictMode
检测资源泄漏,线上监控 OOM 率