【发布时间】:2014-01-02 12:15:32
【问题描述】:
iOS 如何存储从压缩数据(jpeg2000、png、jpg 等)加载的图像
示例:[UIImage imageWithData:pngData]
它是在内部存储实际编码字节并按需解压缩,还是永久解压缩为原始像素或其他格式?
【问题讨论】:
iOS 如何存储从压缩数据(jpeg2000、png、jpg 等)加载的图像
示例:[UIImage imageWithData:pngData]
它是在内部存储实际编码字节并按需解压缩,还是永久解压缩为原始像素或其他格式?
【问题讨论】:
我在 iPad 2 上创建了一个测试应用程序,它使用以下三种方法加载了 200 个 384x384 像素 jpeg2000 图像文件(价值 117,964,800 字节的原始像素):[UIImage imageNamed]、[UIImage imageWithContentsOfFile:] 和 [UIImage imageWithData]。 jpeg2000 文件集是 100 个纹理,然后我将它们复制到额外的 100 个带有“复制”后缀的文件中,以查看 iOS 是否执行任何重复文件检查,它会执行此操作。更多内容请参见下文。
结果如下:
第 1 步:内存只增加了大约所有 jpeg2000 文件的总和(每个文件大约 50K,因此内存增加了大约 5 MB)。我假设此时没有复制重复文件,并且以某种方式被 iOS 合并,因为如果没有重复检查,此时内存将增加 10MB。
第 2 步: 内存显着增加(达到大约 200 MB),可能是因为图像被解码为 BGRA 格式以准备在 UIImageView 中显示。看起来在这个阶段没有重复过滤,并且为每个图像分配了单独的原始内存。我不知道为什么,但这比实际的原始像素内存使用量应该多出大约 80 MB。
第 1 步: 内存使用与 [UIImage imageNamed:] 相同,因此在此阶段进行了重复过滤。
第 2 步:内存使用量增加到 130 MB。出于某种原因,这比 [UIImage imageNamed:] 小 70 MB。这个数字更接近 200 张图像的预期原始像素内存量。
[NSData dataWithContentsOfFile:] 首先使用。
第 1 步:内存使用量为 15 MB。我假设这里没有重复过滤,因为这接近所有 jpeg2000 数据的总文件大小。
第 2 步:内存使用量增加到 139 MB。这比[UIImage imageWithContentsOfFile:] 多,但也不多。
iOS 似乎会引用使用上述三种方法加载的UIImage 的压缩数据,直到实际需要原始像素,然后对其进行解码。
[UIImage imageNamed:] 从未释放内存,因为我所有的图像视图都引用了图像。如果我错开加载并允许运行循环执行,它将释放未引用图像的内存。一个优点是对同一图像的重复[UIImage imageNamed:] 调用基本上是免费的。请勿将此方法用于 GUI 图像以外的任何内容,否则可能会耗尽内存。
[UIImage imageWithContentsOfFile:] 在内存使用方面的行为类似于[UIImage imageNamed:],直到需要原始像素为止,此时由于某种原因它在内存使用方面效率更高。当 UIImage 被释放时,这个方法也会导致内存立即被释放。使用同一文件重复调用 [UIImage imageWithContentsOfFile:] 似乎会使用缓存副本,直到所有引用该文件的 UIImage 都被释放。
[UIImage imageWithData:] 不进行缓存或重复检查,始终创建新图像。
我测试了与 PNG 文件相同的集合,imageNamed 和 imageWithContentsOfFile 的第 1 步结果显示使用的内存更少(大约 0.5 MB),而 imageWithData 显示了所有压缩的 PNG 文件的总和。我的猜测是 iOS 只是存储对文件的引用,并且在解码之前不会对它做任何其他事情。 PNG 的第 2 步结果是相同的。
【讨论】:
[UIImage imageNamed:] 从未刷新其缓存。这是在哪个iOS版本上的?我们已经使用imageNamed: 作为我们的图像缓存很长一段时间了,还没有遇到内存问题。
imageNamed: 在出现内存警告之前不会刷新其缓存,这可能会在随后的运行循环中发生。
一旦加载到内存中,UIImage 就会采用未压缩的RGBA 格式。这意味着图像在内存中占用width x height x 4 字节,其中width 和height 是以像素为单位的图像大小。
UIImage 在某些情况下可能会提供一些优化,但您应该做好以上计划。
更新:
在我看来,上述情况可能并不总是正确的。 UIImage 具有 CGImage 属性。然后是各种功能,如CGImageGetBitmapInfo 和CGImageGetAlphaInfo 以及其他一些相关功能。这些函数的返回值表明图像可以有多种不同的格式。有各种 32 位格式,以及 24 位和 16 位格式。 alpha 可以是第一个、最后一个或根本不存在。并且字节顺序可以是大端或小端。
【讨论】: