Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么在Swift5中,UIImage.jpegData()调用会保留这么多内存?_Swift_Jpeg_Swift5 - Fatal编程技术网

为什么在Swift5中,UIImage.jpegData()调用会保留这么多内存?

为什么在Swift5中,UIImage.jpegData()调用会保留这么多内存?,swift,jpeg,swift5,Swift,Jpeg,Swift5,我有一个运行以下代码段的应用程序-- 观察结果是,在以下代码的步骤中,我将看到一个内存尖峰 let imageData = outputImage.jpegData(compressionQuality: 1) 在整个视图被释放之前,内存峰值不会消失。我确实尝试过一些autoreleasepool()或其他此处建议的put-in DispatchQueue()操作,但显然它们不起作用 为了减少混淆,generateImage()调用不会产生内存泄漏,而只会产生峰值,即generateImage

我有一个运行以下代码段的应用程序--

观察结果是,在以下代码的步骤中,我将看到一个内存尖峰

let imageData = outputImage.jpegData(compressionQuality: 1)
在整个视图被释放之前,内存峰值不会消失。我确实尝试过一些autoreleasepool()或其他此处建议的put-in DispatchQueue()操作,但显然它们不起作用

为了减少混淆,generateImage()调用不会产生内存泄漏,而只会产生峰值,即generateImage()调用后内存立即下降,但我只是将其放在那里,看看这是否相关(我尝试了其他UIImage与jpegData()的关系,但我无法100%再现此问题)

我不太愿意把它称为内存泄漏,因为我相信这个对象(实际上我不知道为什么UIImage.jpegData()调用也消耗了那么多内存,看起来像是Swift内存管理算法的一个bug)最终会在卸载视图时被回收。但是有没有办法避免JPEG数据转换造成的巨大内存消耗或释放内存


(使用此UIImage.jpegData()操作,在我的iPhone上加载4800*60000像素的24MB图像时,内存将增加约100MB)。

4800*6000=28.8M,每像素4字节(RGBA)=1.15亿字节。因此~100MB对于未压缩的数据听起来完全正确,这正是您在
generateImage
中创建的数据。CoreGraphics试图在这些事情上偷懒,因此在您强制它渲染所有内容之前(当您要求
jpegData
时),您可能看不到实际成本

您编写的代码实际上没有意义(您从未定义
outputImage
或使用
newImage
),因此我们不得不猜测很多。您可能正在将
新图像
输出图像
存储在某个位置,而没有向我们显示。可能在属性中,该属性将匹配“当此视图被释放时”

但您似乎也在使用
imageView
显示此图像。如果是这样的话,它将消耗大约100MB的内存,因为它必须解压缩它才能在屏幕上显示。因此,很可能您只是查看图像视图的内存使用情况,这也与“当此视图被释放时”匹配。如果是这种情况,我预计内存使用情况会增加一倍以上(因为您也渲染它,然后压缩它)。但是你可能看不到这个尖峰,因为当你处理完它的时候,内存会被释放,只剩下100MB用于图像视图

(这是“100MB用于图像视图”完全取决于您设置图像视图的方式。如果它直接从文件中读取,则可能会有内存映射压缩数据,并且只应渲染到视图的实际大小。UIImageView非常智能。但是显示大图像总是需要大量内存。最终,您需要字节。)

这段代码试图做什么还不清楚。我怀疑可以更有效地完成(鉴于您似乎已经有了图像视图,我不确定为什么要进行渲染;您应该能够直接操作底层图像)


但最终,如果你想要一个4800*6000像素的RGBA图像,那就需要大约100MB的工作内存来操作。这就是大图像的成本。如果内存太多,则需要减少正在处理的像素数。

有趣的是,下面的代码解决了这个问题,显然这个问题来自generateImage()方法,但我无法解释原因

func generateImage() -> Data {
    // NOTE do not put any of these codes out in case of retain issues of
    // the JPEG data or the images.
    let canvasSize = self.outputImage.size
    UIGraphicsBeginImageContext(canvasSize)
    self.imageView.zoomView?.layer.render(in: UIGraphicsGetCurrentContext()!)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()?.jpegData(compressionQuality: 0)
    UIGraphicsEndImageContext()
    return newImage!
}

我更新了此方法以直接返回数据,而不是返回UIImage,幸运的是,通过此更新,在调用将数据放入某些类变量/缓存后,用于将UIImage转换为JPEG数据(如Rob所述)的内存没有保留。但我还是不太明白其中的原因。也许人们可以发表更多评论?

请澄清您的代码片段与“视图”之间的关系。上面的代码是UIView的子类吗?不要显示“代码片段”。在上下文中向我们展示实际代码。我们不知道你的代码是如何运行的,也不知道图像从哪里来,数据从哪里去。谢谢Rob。但是,您所指的“未压缩数据”是指用于处理JPEG的临时变量吗?为什么UIImage.jpegData()之后会保留此内存?为了显示图像(即在图像视图中),需要一份未压缩的副本。但我的另一点是,您没有给我们提供太多的代码,您可能正在将
generateImage
的结果存储在属性中,在这种情况下不会发布。这就是答案吗?或者你是在问问题的延伸?什么是
generateMasicImage
?这将在未压缩的数据返回之前释放它,而不是返回未压缩的数据。根据您对返回值所做的操作,这可能非常有意义。很难说,因为您没有显示大多数重要的代码,而且您发布的代码与您描述的代码不太匹配,所以我们猜测了很多。例如,当您更改
generateImage()
时,您显然也更改了调用代码,因为签名不同。但你还没有向我们展示这种变化。
func generateImage() -> Data {
    // NOTE do not put any of these codes out in case of retain issues of
    // the JPEG data or the images.
    let canvasSize = self.outputImage.size
    UIGraphicsBeginImageContext(canvasSize)
    self.imageView.zoomView?.layer.render(in: UIGraphicsGetCurrentContext()!)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()?.jpegData(compressionQuality: 0)
    UIGraphicsEndImageContext()
    return newImage!
}