iOS UIImage存储格式,内存使用情况和编码/解码
iOS如何存储从压缩数据加载的图像(jpeg2000,png,jpg等)
例如: [UIImage imageWithData:pngData]
是否在内部存储实际编码字节并按需解压缩,或者是否永久解压缩为原始像素或其他格式?
我使用以下三种方法在[UIImage imageNamed]
, [UIImage imageWithContentsOfFile:]
和[UIImage imageWithData]
上创build了一个加载200 384×384像素jpeg2000图像文件(117,964,800字节的原始像素值)的testing应用程序。 jpeg2000文件集是100个纹理,然后我复制到一个额外的100个带有“复制”后缀的文件中,以查看iOS是否执行任何重复的文件检查。 更多关于下面。
testing分两步完成
- 只需加载图像并将其存储在一个数组中。
- 一个单独的button为每个图像创buildUIImageView并显示它们。
结果如下:
[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:]
似乎使用caching副本,直到所有UIImage
引用文件都被释放。
[UIImage imageWithData:]
没有caching或重复检查,总是创build一个新的图像。
我testing了与PNG文件相同的设置,imageNamed和imageWithContentsOfFile的第1步结果显示使用的内存更less(大约0.5 MB),imageWithData显示所有压缩的PNG文件的总和。 我的猜测是,iOS只是存储对文件的引用,在解码时间之前不会执行任何操作。 PNG的第2步结果是相同的。
一旦加载到内存中, UIImage
就是未压缩的RGBA
格式。 这意味着图像在内存中需要width x height x 4
字节,其中width
和height
是以像素为单位的图像大小。
在某些情况下, UIImage
可能会提供一些优化,但是您应该在上面进行计划。
更新:
我觉得以上情况并非总是如此。 UIImage
具有CGImage
属性。 然后有像CGImageGetBitmapInfo
和CGImageGetAlphaInfo
和其他一些相关的函数的各种function。 这些函数的返回值表示图像可以有许多不同的格式。 有各种32位格式,以及24位和16位格式。 alpha
可以是第一个,最后一个,或者根本不存在。 字节顺序可以是大或小的。