侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

设计高性能图片加载框架并解决内存抖动问题

2025-12-11 / 0 评论 / 4 阅读

题目

设计高性能图片加载框架并解决内存抖动问题

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

Bitmap内存管理,内存抖动优化,三级缓存设计,弱引用与LRU策略,Glide源码原理

快速回答

实现高性能图片加载框架的关键点:

  • 采用三级缓存架构:内存缓存(LruCache + 弱引用)、磁盘缓存、网络加载
  • 使用LruCache管理Bitmap内存,结合弱引用防止内存泄漏
  • 通过Bitmap复用池(inBitmap)减少内存分配
  • 采用对象池模式复用请求对象,避免频繁GC
  • 根据View尺寸进行采样压缩(inSampleSize + inJustDecodeBounds)
## 解析

核心架构设计

三级缓存流程:

  1. 检查活动缓存(弱引用持有正在使用的Bitmap)
  2. 检查LruCache内存缓存
  3. 检查磁盘缓存(DiskLruCache)
  4. 网络下载并写入各级缓存

内存抖动优化方案

// Bitmap复用池实现
public class BitmapPool {
    private final Set<Bitmap> pool = Collections.synchronizedSet(new HashSet<>());

    public Bitmap get(int width, int height) {
        for (Bitmap bmp : pool) {
            if (bmp.isRecycled()) continue;
            if (bmp.getWidth() == width && bmp.getHeight() == height) {
                pool.remove(bmp);
                return bmp;
            }
        }
        return null;
    }

    public void put(Bitmap bitmap) {
        if (bitmap != null && !bitmap.isRecycled()) {
            pool.add(bitmap);
        }
    }
}

关键优化技术

  • LruCache 实现:
    int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
    int cacheSize = maxMemory / 8;
    LruCache<String, Bitmap> memoryCache = new LruCache<>(cacheSize) {
        protected int sizeOf(String key, Bitmap value) {
            return value.getByteCount() / 1024;
        }
        protected void entryRemoved(boolean evicted, String key, 
            Bitmap oldValue, Bitmap newValue) {
            bitmapPool.put(oldValue); // 移出时放入复用池
        }
    };
  • 采样压缩:
    先读取图片边界(inJustDecodeBounds=true),根据View尺寸计算inSampleSize
  • 弱引用缓存:
    private Map<String, WeakReference<Bitmap>> activeCache = new HashMap<>();

最佳实践

  • 使用RGB_565格式替代ARGB_8888(内存减少50%)
  • 监听onTrimMemory动态调整缓存大小
  • 网络层使用OkHttp连接池复用TCP连接
  • 磁盘缓存采用Journal日志保证数据一致性

常见错误

  • 未处理Configuration变更导致重复加载
  • ListView/RecyclerView中未使用ViewTag引发图片错位
  • 主线程解码大图导致ANR
  • 弱引用缓存未与LruCache联动造成内存泄漏

扩展知识

  • Glide源码设计:
    • EngineJob协调加载流程
    • ResourceRecycler管理Bitmap生命周期
    • Downsampler处理采样逻辑
  • Android 8.0后:使用NativeAllocationRegistry替代inBitmap
  • 内存抖动监控:通过Allocation Tracker分析分配模式