侧边栏壁纸
博主头像
colo

欲买桂花同载酒

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

设计一个高性能的图片缓存组件

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

题目

设计一个高性能的图片缓存组件

信息

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

考点

内存管理,磁盘存储,多线程处理,缓存策略,性能优化

快速回答

设计高性能图片缓存需实现:

  • 三级缓存架构:内存缓存(NSCache)+ 磁盘缓存(文件系统)+ 网络下载
  • 线程安全:使用串行队列管理读写操作
  • 缓存淘汰策略:LRU内存管理 + 文件过期清理
  • 解码优化:后台线程解码图片并缩放至视图尺寸
  • 请求合并:对相同URL的并发请求进行合并
## 解析

核心架构设计

高性能图片缓存应包含三级结构:

class ImageCache {
    // 1. 内存缓存(线程安全访问)
    private let memoryCache = NSCache<NSString, UIImage>()

    // 2. 磁盘缓存目录
    private let diskCacheURL: URL

    // 3. 操作队列与状态管理
    private let serialQueue = DispatchQueue(label: "com.imageCache.queue")
    private var runningRequests = [String: [ImageRequest]]()
}

关键技术实现

1. 内存缓存优化

  • 使用NSCache自动释放内存(优于Dictionary
  • 设置成本计算:memoryCache.totalCostLimit = 1024 * 1024 * 100 // 100MB
  • 成本计算规则:cost = image.size.height * image.size.width * 4(RGBA)

2. 磁盘缓存实现

// 文件存储路径
func storeToDisk(data: Data, key: String) {
    let fileURL = diskCacheURL.appendingPathComponent(key)
    try? data.write(to: fileURL)
}

// 使用FileManager属性记录访问时间
let attributes: [FileAttributeKey: Any] = [
    .creationDate: Date(),
    .modificationDate: Date() // 用于LRU
]

3. 多线程处理

  • 下载队列OperationQueue限制最大并发数
  • 解码队列:专用后台队列处理CPU密集型解码
  • 回调主线程DispatchQueue.main.async更新UI

4. 请求合并机制

func loadImage(url: URL, completion: @escaping (UIImage?) -> Void) {
    serialQueue.async {
        // 存在相同请求时追加回调
        if var existingRequests = self.runningRequests[url.absoluteString] {
            existingRequests.append(ImageRequest(completion: completion))
            return
        }

        // 创建新请求
        let request = ImageRequest(completion: completion)
        self.runningRequests[url.absoluteString] = [request]

        self.startDownload(url: url) // 触发下载
    }
}

缓存策略实现

LRU内存淘汰

// 使用双向链表实现
class LRUCacheNode {
    let key: NSString
    var value: UIImage
    var prev: LRUCacheNode?
    var next: LRUCacheNode?
}

// 访问时移动节点到链表头部
func moveToHead(_ node: LRUCacheNode) {
    removeNode(node)
    addToHead(node)
}

磁盘清理策略

  • 后台定期清理(如App进入后台时)
  • 按文件修改时间排序,删除最旧文件
  • 设置最大磁盘空间(如200MB)

性能优化点

  • 解码优化:使用UIGraphicsImageRenderer替代UIGraphicsBeginImageContext
  • 降采样:对大图使用ImageIO进行缩略图解码
  • 预加载:对即将显示的图片触发低优先级下载

常见错误

  • 线程爆炸:未限制下载队列并发数导致卡顿
  • 内存峰值:同步解码大尺寸图片阻塞主线程
  • 缓存穿透:未处理重复请求导致多次下载
  • 磁盘碎片:频繁小文件写入降低IO性能

扩展知识

  • 渐进式加载:支持JPEG渐进式渲染
  • 格式优化:根据设备选择HEIC/JPEG格式存储
  • 响应式设计:监听UIApplication.didReceiveMemoryWarningNotification清空内存缓存
  • 性能指标:使用Instruments的Core Animation和Time Profiler调试