less than 1 minute read

压缩解码图片

这一篇不再顺着主流程继续往下读,而是单独补一个很关键、但又特别容易被忽略的话题:图片解码 / 解压缩

先说明一下背景:我这组文章分析的是 SDWebImage 4.4.1。后续版本实现细节当然会有变化,但“为什么图片解码会影响性能和内存”这个问题本身并没有过时。

为什么这个问题重要

图片框架真正难的地方,很多时候并不是“怎么把图片下载下来”,而是:

  1. 图片文件通常是压缩格式;
  2. 真正显示到屏幕上时,系统往往要把它解码成位图数据;
  3. 一旦图片很多、图片很大、或者解码时机不合适,卡顿和内存问题就会一起冒出来。

也就是说:

  • 磁盘上的图片文件有多大;
  • 解码后在内存里会占多少空间;

这两件事完全不是一回事。

文件体积小,不代表内存占用小

比如一张 JPEG 图片,在磁盘上可能只有几百 KB;但只要它真正被解码成位图,内存占用往往就会按像素来算。

一个很粗略的估算公式是:

宽 × 高 × 每像素字节数

如果按常见的 RGBA 来算,一张 1000 × 1000 的图片,解码后大概就是:

1000 × 1000 × 4 ≈ 4MB

所以很多时候,真正可怕的不是“下载包有多大”,而是解码后的位图到底有多大

为什么框架会提前做解压缩

从体验上看,把图片解码 / 解压缩这件事提前做掉,有一个非常现实的好处:

  • 避免图片第一次显示时,主线程临时做大量解码工作;
  • 降低滚动列表或批量展示图片时的卡顿风险;
  • 把本来会发生在渲染临门一脚的工作,尽量往前挪。

所以这本质上就是一种很典型的:

空间换时间

也就是:

  • 花更多内存;
  • 换更平滑的显示体验。

什么时候会出问题

这个策略不是永远都赚。

如果图片本身很大,或者同一时间解码的图片很多,那么“提前解压缩”反过来就可能把内存迅速推高,最后出现:

  • 列表滚动时内存暴涨;
  • 大图第一次出现时瞬间抬升;
  • 缓存和解码结果同时存在,内存压力明显变重。

所以这一块没有绝对答案:

  • 小图、常见列表图:提前解压缩,通常更划算;
  • 大图、长图、高清原图:就需要更谨慎地设计。

一个更务实的理解

如果只想先抓一句话,我觉得可以记成:

图片框架真正难的地方,不是“下载”,而是下载、缓存、解码、显示、内存这几件事之间的平衡。

而图片解码 / 解压缩,正是这个平衡点里最容易被忽略、但也最容易出事故的一环。

补充阅读

这部分如果要系统看,推荐直接看这篇文章:

这里的知识点确实比较多,但如果你想真正搞懂“为什么图片会卡、为什么大图会涨内存”,这篇值得认真看。

Updated: