【问题标题】:iOS UIImage storage formats, memory usage and encoding / decodingiOS UIImage存储格式、内存使用和编码/解码
【发布时间】:2014-01-02 12:15:32
【问题描述】:

iOS 如何存储从压缩数据(jpeg2000、png、jpg 等)加载的图像

示例:[UIImage imageWithData:pngData]

它是在内部存储实际编码字节并按需解压缩,还是永久解压缩为原始像素或其他格式?

【问题讨论】:

    标签: ios image png jpeg


    【解决方案1】:

    我在 iPad 2 上创建了一个测试应用程序,它使用以下三种方法加载了 200 个 384x384 像素 jpeg2000 图像文件(价值 117,964,800 字节的原始像素):[UIImage imageNamed][UIImage imageWithContentsOfFile:][UIImage imageWithData]。 jpeg2000 文件集是 100 个纹理,然后我将它们复制到额外的 100 个带有“复制”后缀的文件中,以查看 iOS 是否执行任何重复文件检查,它会执行此操作。更多内容请参见下文。

    测试分两步完成

    1. 只需加载图像并将它们存储在一个数组中。
    2. 一个单独的按钮为每个图像创建 UIImageViews 并显示它们。

    结果如下:

    [UIImage imageNamed:]

    第 1 步:内存只增加了大约所有 jpeg2000 文件的总和(每个文件大约 50K,因此内存增加了大约 5 MB)。我假设此时没有复制重复文件,并且以某种方式被 iOS 合并,因为如果没有重复检查,此时内存将增加 10MB。

    第 2 步: 内存显着增加(达到大约 200 MB),可能是因为图像被解码为 BGRA 格式以准备在 UIImageView 中显示。看起来在这个阶段没有重复过滤,并且为每个图像分配了单独的原始内存。我不知道为什么,但这比实际的原始像素内存使用量应该多出大约 80 MB。

    [UIImage imageWithContentsOfFile:]

    第 1 步: 内存使用与 [UIImage imageNamed:] 相同,因此在此阶段进行了重复过滤。

    第 2 步:内存使用量增加到 130 MB。出于某种原因,这比 [UIImage imageNamed:] 小 70 MB。这个数字更接近 200 张图像的预期原始像素内存量。

    [UIImage imageWithData:]

    [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: 作为我们的图像缓存很长一段时间了,还没有遇到内存问题。
    • iOS 6 和 7 都经过测试,从未释放内存
    • 这一切都在一个运行循环中吗?我想知道问题是否在于imageNamed: 在出现内存警告之前不会刷新其缓存,这可能会在随后的运行循环中发生。
    • 这是一个电话。我将再次运行它,并为每个调用异步调度。
    • 错开加载似乎有所帮助,尽管我仍然在屏幕上出现大量图像视图时崩溃。我仍然会错误地将 imageNamed 仅用于 GUI 元素,而将 imageWithContentsOfFile 用于任何大的、临时的或用户生成的东西。
    【解决方案2】:

    一旦加载到内存中,UIImage 就会采用未压缩的RGBA 格式。这意味着图像在内存中占用width x height x 4 字节,其中widthheight 是以像素为单位的图像大小。

    UIImage 在某些情况下可能会提供一些优化,但您应该做好以上计划。

    更新:

    在我看来,上述情况可能并不总是正确的。 UIImage 具有 CGImage 属性。然后是各种功能,如CGImageGetBitmapInfoCGImageGetAlphaInfo 以及其他一些相关功能。这些函数的返回值表明图像可以有多种不同的格式。有各种 32 位格式,以及 24 位和 16 位格式。 alpha 可以是第一个、最后一个或根本不存在。并且字节顺序可以是大端或小端。

    【讨论】:

    • 查看我的更新答案。似乎有许多可能的格式。有关我提到的功能,请参阅文档。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    相关资源
    最近更新 更多