各类型图片占用内存是否一致?

问题一:各类型图片占用内存是否一致?

  • 对比类型 png、jpg、webp、gif 等。(如果对于 png8、png24 或者其他压缩、连续等操作有影响也可以说明)
  • 相同大小 300*300
  • 占用浏览器内存。看清楚是内存别说存储大小

如果有不同平台的资料也可以,比如说 PC vs 移动端,Android vs iOS,甚至可以 Android4 vs Android5

问题二:如何评测证实

基于上述内容和答案,如何做评测呢?看了 performance monitor 和 浏览器自带的任务管理器并没有明显变化。

PC 客户端打了一个 chrome 49 版本中,如果一个页面加载上千张图片,会被客户端杀掉。所以我理解这个内存其实是可以被观测的。

问题三:对于其他图片其他替代品呢?

图片(<img>)相比比较 背景图、canvas、svg 有会有哪些差异呢?内存?CPU?

阅读 6.2k
4 个回答

首先要定义题目里的“内存”到底指什么。

如果是指狭义上的 RAM,那么其实是有区别的 ———— 毕竟图片文件本身要读到内存里去。并且部分压缩存储的图片格式还需要“解压缩”,这部分也是额外有开销的。

如果是广义上的内存,GPU 显存(即 VRAM)也是一种内存,那么是基本没区别的。此时 VRAM 处理的已经是 Bitmap 位图了,实际占用只与位图格式(注意,是位图格式,不是图片存储格式)有关,约等于宽×高×位深


题主没有观测到明显差距可能是原始数值上差距本身就不大。我们可以手动构造相差悬殊的图片来模拟测试。

我们可以准备四张不同存储格式、但分辨率均为 4096×4096 的单一纯色图片,可以观察到文件大小相差很大,最大的和最小的可以相差近 200 倍。

image.png

再准备一个空白的 HTML 文件,里面只包含一句 <img src="./test.FMT">,分别填入四种格式,

为消除偶然性误差,可在多个设备上反复进行多次操作,结果取中位数。

image.png

P.S. Chrome 有 Occlusion Tracking 技术,所以为消除由此带来的影响,上述数值全部读取自活动标签页情况下。

我们只关注图上的三个指标就可以了。

我们会发现 RAM 占用上其实有明显的差距,Image Cache 约等于文件大小,而 VRAM 占用基本相同。(其实 GIF 格式的表现比较奇怪,具体为啥我就没再深究,可能是 GIF 最后转换出来的位图格式跟其他几个不同、系统自己做了判断和优化?)

  1. 纯猜测未经查证,相同尺寸的图片内存占用应该是一样,解析之后会转成相同颜色深度的位图数据,如32位 rgba,又或者某种统一格式的纹理?
  2. chrome 89之后,确实有performance-measure-memory可以测量内存占用,不过考虑到大型应用程序各种内存池的使用,尤其chrome这种把空间换时间用到极致的,应该很难精确了解多加一张图片之后对内存的影响。我简单的试了一下:

    let large_string = "";
    let image_jpg;
    let image_png;
    async function printMemory(label) {
      const obj = await performance.measureUserAgentSpecificMemory();
      const memory = obj.bytes / 1000000;
      console.log(label, `${memory.toFixed(2)}MB`, Date.now());
    }
    
    async function loadImage(src) {
      const img = new Image();
      img.src = src;
      await new Promise((resolve) => (img.onload = resolve));
      document.body.appendChild(img);
      return img;
    }
    
    !(async function bootstrap() {
      // make a large string
      large_string = "O".repeat(10000000);
      large_string[0];
      await printMemory("after large string: ");
    
      image_jpg = await loadImage("tb.jpg");
      await printMemory("after jpg loaded: ");
    
      document.body.removeChild(image_jpg);
      image_jpg = null;
      await printMemory("after jpg removed: ");
    
      image_png = await loadImage("tb.png");
      await printMemory("after png load: ");
      document.body.removeChild(image_png);
      image_png = null;
      await printMemory("after png removed: ");
    })();
    API is available as an origin trial
    如果要本地看效果的话,得对输出网页设置一下http头。
    app.get("/", (req, res) => {
      res.setHeader("cross-origin-embedder-policy", "require-corp");
      res.setHeader("cross-origin-opener-policy", "same-origin");
    })
  3. 图片与背景图,svg,从浏览器程序的角度应该是一样,无非数据格式不一样,有位图有矢量图,canvas 比较特殊,它是唯一可以在浏览器这个主要是 retained mode 的环境中可以使用 immediate mode 的入口,我认为它和其他的html element 有本质的区别。
  1. 应该是一样的。因为图片都会转换成 bitmapData,再渲染。不过渲染过程消耗的资源可能不一样。
  2. 没法评测证实。可以试试翻浏览器源码。
  3. 一样的。svg 应该会有明显差异,因为 SVG 可以交互。

各类型图片占用内存是不一样的
实际上,现有图片格式基本都是压缩格式,即使分辨率相同,像素量相同,但是图片的复杂度会使压缩算法得到不同的结果,类似你一张全白的图片,因为所有像素都是一个数值,这个可以用很少的空间占用来记录,所以就可以很小的容量了。另外,JPG压缩算法可以有不同的压缩比,这样即使相同图片相同分辨率也可以有不同的占用空间尺寸了。
如果两张图片大小(尺寸)一样,就算是同一种存储格式占内存也不一定一样,每幅图像矩阵元素不同运算后大小也就不同。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题