内存问题不是“用一阵子就变慢”,而是“应用增长过程中必然出现的工程成本”。本篇从内存结构、诊断流程、泄漏定位到图片缓存优化,给你一套能直接落地的实践路线。
1. 内存问题的三类根因
常见内存问题可以分为:
- 缓存过大:图片、网络数据、列表预渲染
- 对象堆积:全局单例持有引用,生命周期不回收
- 重复创建:大量短生命周期对象高频创建
目标不是“消灭内存”,而是把内存维持在稳定区间,避免持续增长。
2. 诊断流程:先确认增长曲线
基本流程:
- 进入典型高压页面(图片/列表/富文本)
- 使用 DevTools 的 Memory 视图观察堆曲线
- 触发 GC,看是否能回落
如果曲线持续上升且 GC 后不回落,基本可以判定泄漏。
3. 典型泄漏源:全局引用
最常见的泄漏场景是“全局持有引用”。
class CacheStore {
CacheStore._();
static final CacheStore instance = CacheStore._();
final Map<String, Object> _cache = {};
void put(String key, Object value) {
_cache[key] = value;
}
void clear() {
_cache.clear();
}
}
问题:如果不清理,缓存会一直增长。
建议:给缓存上限,或用 LRU 策略。
class LruCache<K, V> {
LruCache(this.maxSize);
final int maxSize;
final _map = <K, V>{};
void put(K key, V value) {
if (_map.length >= maxSize && !_map.containsKey(key)) {
_map.remove(_map.keys.first);
}
_map[key] = value;
}
V? get(K key) => _map[key];
}
4. 图片缓存优化:避免无上限增长
Flutter 默认图片缓存是 ImageCache,可以通过 PaintingBinding 控制。
void configureImageCache() {
final cache = PaintingBinding.instance.imageCache;
cache.maximumSize = 200; // 图片数量限制
cache.maximumSizeBytes = 80 * 1024 * 1024; // 80MB
}
建议:
- 列表页使用缩略图
- 大图只在详情页加载
- 超大图片优先压缩再显示
5. 列表与滚动的内存控制
列表内存问题多来自 item 过大或无限缓存。
ListView.builder(
cacheExtent: 600,
itemBuilder: (context, index) => ItemCard(index: index),
itemCount: 500,
);
建议:
cacheExtent适当设置- item 尽量轻量,避免深层嵌套
6. 实战小结:稳定曲线才是优化成功
你要追求的不是“内存最低”,而是:
- 内存增长可控
- GC 后能回落
- 长时间使用保持稳定