我目前正在开发一个应用程序,这个应用程序一个接一个地显示许多图像。我没有奢侈的使用视频,不幸的是,我可以选择图像编解码器的使用。数据从服务器发送到已编码的应用程序。
例如,如果我使用PNG或JPEG,我可以使用UIImage将接收到的数据转换为[[UIImage alloc] initWithData:some_data]。当我使用一个原始字节数组,或者另一个必须首先解码为原始字节数组的自定义编解码器时,我必须创建一个位图上下文,然后使用CGBitmapContextCreateImage(bitmapContext)给出一个CGImageRef,然后将其输入[[UIImage alloc] initWithImage:cg_image]。这要慢得多。

上面的图表(时间以秒为单位)是执行从NSData到UIImage转换所需的时间。PNG、JPEG、BMP和GIF几乎都是相同的。Null根本不影响转换,而是返回零。Raw是使用位图上下文方法转换的raw RGBA字节数组。自定义解压缩为原始格式,然后做同样的事情。LZ4是原始数据,使用LZ4算法进行压缩,因此它还通过位图上下文方法运行。
例如,PNG图像就是被压缩的位图图像。这个解压缩,然后渲染所花费的时间少于我对原始图像的渲染。iOS一定是在幕后做些什么来加快速度。
如果我们查看转换每个类型所需的时间以及绘制(到图形上下文)所需的时间,我们将得到以下结果:

我们可以看到,大多数图像需要非常不同的时间转换,但在绘画时间是相当相似的。这就排除了UIImage懒惰并仅在需要时才进行转换的任何性能提升。
我的问题本质上是:对于众所周知的编解码器来说,更快的速度是我可以利用的吗?或者,如果没有,还有其他方法可以更快地呈现我的原始数据吗?
编辑:为了记录,每当我得到一个新的UIImage时,我都会在另一个上绘制这些图像。也许有一种更快的选择,我愿意去研究。然而,不幸的是,OpenGL不是一种选择。
进一步编辑:这个问题是相当重要的,我想得到最好的答案。赏金将在期限届满后颁发,以确保提供尽可能好的答案。
最后编辑:我的问题是为什么不解压缩和绘制一个原始的RGBA数组比绘制一个PNG要快,因为PNG必须解压缩到一个RGBA数组,然后再绘制。其结果是,它实际上更快。然而,这似乎只是在版本构建中的情况。调试构建没有为此进行优化,但是在幕后运行的UIImage代码显然是。通过作为发布版本进行编译,RGBA数组的映像比其他编解码器快得多。
发布于 2014-08-11 09:43:42
在测量性能时,为了找到瓶颈,测量完整的流水线是很重要的。
在您的情况下,这意味着您不能隔离UIImage创建。你将不得不包括图像显示-否则你陷入陷阱,只测量你感兴趣的一部分。
UIImage是,而不是,它是一个围绕位图数据的薄包装,而是一个相当复杂和优化的系统。例如,底层CGImage只能引用磁盘上的一些压缩数据。这就是为什么使用initWithContentsOfFile:或initWithData:初始化一个initWithData:非常快的原因。在ImageIO和Quartz框架中,iOS中有更多隐藏的性能优化,所有这些都会增加您的度量。
获得可靠测量数据的唯一可靠方法是做您真正想做的事情(从网络或磁盘获取数据,以某种方式创建一个UIImage,并在屏幕上显示它至少一个帧)。
以下是您应该注意的一些注意事项:
CGBitmapContext创建图像。所以除非有必要,否则不要这么做。backboardd (iOS中使用的窗口服务器类型)中进行.结论:
您的目标应该是为您的真实场景找到瓶颈。因此,不要使用虚构的测试数据和人为的代码进行测试。最后,您可能会优化应用程序中没有使用的代码路径的性能。
当您将测试代码更改为测量完整的管道时,如果您能够根据结果更新您的问题,那就太好了。
发布于 2014-08-11 09:04:01
UIImage使用和抽象最适合实际源的内部表示,因此具有良好的性能。PNG图像不被转换为位图,然后由UIImage显示,而是更有表现力的绘图。
另一方面,位图是处理图像的最大、低效率和繁重的方法,因此除了将它们转换为另一种格式之外,没有什么可以做的。
发布于 2014-08-11 11:33:29
[UIImage initWithData:]不复制任何内存。它只是把内存留在原来的地方,然后当你画出来的时候,它会将内存转储到GPU上去做它的事情--而CPU或RAM在解码图像时没有太多的参与。这一切都是在GPU的专用硬件中完成的。
记住,苹果公司设计自己的CPU/GPU是通过授权其他制造商的技术和定制来满足他们的需要。他们有一千多个CPU硬件工程师,他们只在一台芯片组上工作,而有效地处理图像是一个优先事项。
您的低级代码可能会执行大量内存复制和数学运算,这就是为什么它要慢得多的原因。
UIImage和NSData是非常智能的高性能API,几十年来由真正了解(甚至构建)硬件和内核的人开发。除非您准备编写数千行代码,并花费数月甚至几年的时间进行测试和调整以获得更好的性能,否则它们的效率要比使用较低级别的API高得多。
例如,NSData可以毫不费力地处理兆字节的数据,具有良好的性能,尽管可能只有几千兆字节的内存可用--正确地使用它可以无缝地将RAM和SSD/HDD存储结合起来,其性能通常类似于您实际拥有to内存时所能得到的性能,而UIImage可以检测低内存情况,并在没有任何代码的情况下释放几乎所有的内存--如果它知道图像最初加载的URL (对于文件://‘s比http:// URL更好)。
如果您可以使用UIImage和NSData来做您想做的事情,那么您应该这样做。只有当您有其他无法实现的特性时,才可以使用较低级别的API。
https://stackoverflow.com/questions/25207819
复制相似问题