我们有一个模仿Camu app行为的应用程序,当过滤时,过滤器会被屏蔽在彼此之上。但是,在我们的应用程序中,我们只对已捕获的图像执行此操作,因此不用于实时相机预览,如Camu也可以。
当用户选择了图像时,我们使用查找表(LUT)预先处理所有过滤器(在我们的例子中为8),这样就可以快速浏览它们,而无需等待每个过滤器首先处理。一切都按预期工作。但是,在处理过滤器时,应用程序会消耗大量内存(至少 100MB)。这对于只有512MB RAM的旧设备来说是一个问题,由于内存压力,这常常会导致崩溃。
我们无法理解的是,当GPUImage框架可以使用30 fps的应用过滤器轻松处理实时摄像头馈送时,为什么必须消耗这么多内存,而不会出现任何打嗝。
为了减少过多的内存消耗,我们尝试了几种方法,例如以较低分辨率处理图像(这确实产生了积极影响,但还不够),并将过滤后的图像输出到GPUImageView
代替一个UIImageView
。
要么我们只是错误地使用它,要么我们只是不理解这个非常出色的框架的内部运作。
这是我们用于处理过滤器的代码:
- (UIImage *)image:(GPUImagePicture *)originalImageSource filteredWithLUTNamed:(NSString *)lutName
{
GPUImagePicture *lookupImageSource = [[GPUImagePicture alloc] initWithImage:[UIImage imageNamed:lutName]];
GPUImageLookupFilter *lookupFilter = [[GPUImageLookupFilter alloc] init];
if (originalImageSource.outputImageSize.height > kMaxProcessingSize || originalImageSource.outputImageSize.width > kMaxProcessingSize)
[lookupFilter forceProcessingAtSizeRespectingAspectRatio:_maxProcessingSize];
[originalImageSource addTarget:lookupFilter];
[lookupImageSource addTarget:lookupFilter];
[lookupFilter useNextFrameForImageCapture];
[originalImageSource processImage];
[lookupImageSource processImage];
return [lookupFilter imageFromCurrentFramebuffer];
}
根据我们使用Instruments进行的分析,大部分内存都是围绕processImage
和imageFromCurrentFramebuffer
方法使用的。
以下是由上述代码引起的内存峰值示例:
我们非常感谢任何反馈,这些反馈可能会让我们理解为什么就是这种情况,或者是一个能够大大减少内存消耗的实际解决方案。
答案 0 :(得分:1)
在上面的代码中,有两个临时分配大量内存的地方:使用-imageNamed:
从文件创建UIImage,以及随后根据该文件创建GPUImagePicture(其中导致为该图像上传OpenGL纹理)。这将导致内存激增,因为它们已被分配。
在方法运行完成后应该取消分配这些内容,但使用-imageNamed:
会导致缓存,这可能会导致查找图像在内存中停留的时间超出预期。您可以通过调用
[[GPUImageContext sharedFramebufferCache] purgeAllUnassignedFramebuffers];
您可以在使用上述方法之前或之后尝试调用此方法。
我在幕后使用帧缓冲缓存机制导致OpenGL帧缓冲区及其附加纹理被回收,但是一个接一个地创建一系列图像可能会使这种缓存短路并导致这些帧缓冲区在缓存中建立。
最后,您将在接近结尾的-imageFromCurrentFramebuffer
行创建一个自动释放的UIImage。如果在从此方法获取新方法之前未处理此方法的输出UIImage,则这些大图像将在内存中累积。您可能需要将上面的内容包装在一个显式的自动释放池中,该池在处理图像时会耗尽,以确保每次通过此方法时都会释放UIImages。