与 CGContextDrawImage 相比,为啥 UIImageView 如此占用内存

Posted

技术标签:

【中文标题】与 CGContextDrawImage 相比,为啥 UIImageView 如此占用内存【英文标题】:Why is UIImageView so memory intensive compared to CGContextDrawImage与 CGContextDrawImage 相比,为什么 UIImageView 如此占用内存 【发布时间】:2011-06-24 17:40:44 【问题描述】:

开发 iPad PDF 阅读器时,我们决定准备渲染密集页面(其中有很多路径)的高分辨率图像,并使用这些图像而不是 pdf 页面来避免性能问题。我们认为 3*768 by 3*1024 是可读性和渲染性能之间的一个很好的折衷方案,它会产生 ~1.5 MB jpegs

不过,我们测试了两种用于显示图像页面的实现。一个使用CATiledLayer 子类,该子类还负责处理“普通”PDF 页面(使用CGContextDrawImage 绘图),另一个使用UIImageView。后者的优点是显示和缩放非常快,但内存使用量非常糟糕 - 大约需要 30 MB 内存(这与图像的位图大小一致)。另一种方法 (CATiledLayer) 需要更多时间来首次显示页面,并且在缩放后还需要两秒钟来重新渲染(类似于 pdf 页面,但速度更快),但不会占用比显示页面更多的内存小得多的图像或 PDF 页面。

有谁知道幕后发生了什么,以及是否可以通过使用 Quartz 框架将 CGContextDrawImage 的低内存使用率与 UIImageView 的高性能结合起来。

【问题讨论】:

【参考方案1】:

不确定这个问题是否仍然相关,但如果是的话,也许这会有所帮助:

我也在我的tiled image view 中进行了有效显示大视图的战斗。这个问题有很多潜在的部分:

普通的UIView,包括UIImageView,似乎总是完全由内存来支持它的图像。即使您实现drawRect: 方法,它似乎总是通过视图的整个边界,而不仅仅是滚动视图中可见的区域。正如您所发现的,这很快会占用大量内存,因为每个像素需要 4 个字节。 CATiledLayer确实只请求可见磁贴的内容。它还会丢弃不再可见的图块——这就是内存节省的来源。但是,它在后台线程上执行通知和绘图,同时从白色动画到内容。似乎是通过私有 API 来实现的,我还没有找到将CATiledLayer 的功能重新实现为我自己的CALayer 子类的方法,因为似乎没有我们可以使用的通知机制凡人。 如果您在滚动视图中有多个视图,它们在被分页时会适当地收到drawRect: 消息。不过,UIKit 似乎很难处理视图下方的子视图过多。

对于您,我可以看到几个可能的选项:

也许可以挽救基于CATiledLayer 的实现。 fadeDuration 默认为 0.25 秒,如果您的加载时间很短,这可能会太长。您可以将其直接放到1.0/60.0 之类的位置,即一帧。从您的描述中不清楚的一件事是您的图像是覆盖整个页面大小还是仅覆盖每个 256x256 像素的图块。为每个图块一遍又一遍地解码整个 JPEG 比解码单个图块文件要慢得多。 如果从CATiledLayer 线程执行所有操作的延迟太高,您可以手动创建一堆图块作为UIImageView 子视图到空白UIView 这是滚动视图的主要子视图。这些子视图中的每一个都被分配了自己的平铺图像。如果幸运的话,UIKit 会很聪明,可以删除这些视图的内容并按需重新加载相应的 JPEG。 如果 UIImageViews 不够聪明,或者你有太多的视图让 UIKit 应付,你可以构建自己的视图,在drawRect: 中加载它们的 JPEG。如果它仍然太生涩,请尝试使用您自己的 CALayers,这将是您的单一视图的空白层的子层,并再次按需加载它们的图像。这就是我最终采用的平铺图像视图。

这应该包括滚动,但如果您允许用户缩小(缩小),它仍然可能非常慢。在这种情况下,我建议您存储适当的低分辨率版本并以最外层的缩放级别加载/显示这些版本。

【讨论】:

非常感谢您提供的详细而有启发性的答案。尽管我实际要求的项目已经完成,但我相信您的解释将对即将发生的问题有所帮助,而且 - 如果没有 - 很高兴知道。

以上是关于与 CGContextDrawImage 相比,为啥 UIImageView 如此占用内存的主要内容,如果未能解决你的问题,请参考以下文章

CGContextDrawImage 在 iPhone 4 上非常慢

CGContextDrawImage(Swift)上的间歇性“释放对象的校验和不正确”错误

巨大的内存峰值 - CGContextDrawImage

CGContextDrawImage 画大图很模糊

Swift 3 和 CGContextDrawImage

-[UIImage drawInRect:] / CGContextDrawImage() 不释放内存?