【问题标题】:GPUImage memory errorGPUImage内存错误
【发布时间】:2015-02-06 00:59:28
【问题描述】:

我正在向 iOS 上录制视频的帧图像添加失真效果。对于分辨率为 640 x 640 的 14 秒视频,应用程序因内存错误而崩溃。我认为所有内存都被正确释放了。

我觉得很奇怪,分析器告诉我应用程序最大消耗大约 20 MB!我也找不到内存泄漏。 CoreImage 库在整个处理过程中确实积累了大约 580 MB 的内存,但内存在处理完每个帧后都会释放,因此不会导致崩溃。

如果我将失真过滤器注释掉,一切正常,所以我假设错误在过滤部分。我正在安装 iOS 8 的 iPhone 5s 上进行测试。

这是 GPUImage 中的错误吗? 为什么我无法分析过多的内存消耗?

感谢每一个回答! :)

这是相关的代码:

- (CIImage *) render:(CIImage*)targetImage imageContext:(CIContext*) imageContext
        facialFeatures:(NSArray*)facialFeatures currentFrameInd:(int)frameInd
{
    if ( !facialFeatures ) return targetImage;

    @autoreleasepool {
        CGImageRef inputImage = [imageContext createCGImage:targetImage fromRect:[targetImage extent]];

        GPUImagePicture *sourcePicture = [[GPUImagePicture alloc] initWithCGImage:inputImage];
        GPUImageOutput *currentOutput = sourcePicture;

        // Search through multiple faces.
        for ( ArtechFacialFeature *facialFeature in facialFeatures ) {
            // Create the distortion for one face.
            for ( ArtechImageDistortionDescription *distortion in distortions ) {
                GPUImageFilter *imageFilter = [self createDistortionFilter:distortion
                    facialFeature:facialFeature imageExtent:targetImage.extent];

                [currentOutput addTarget:imageFilter];
                currentOutput = imageFilter;
            }
        }

        [currentOutput useNextFrameForImageCapture];
        [sourcePicture processImage];

        UIImage *currentFilteredVideoFrame = [currentOutput imageFromCurrentFramebuffer];

        targetImage = [targetImage initWithCGImage:currentFilteredVideoFrame.CGImage];

        [sourcePicture removeAllTargets];

        currentFilteredVideoFrame = nil;
        sourcePicture = nil;

        currentOutput = nil;

        CFRelease( inputImage );
    }

    return targetImage;
}

【问题讨论】:

  • 这个答案将帮助您采取内存预防措施 - stackoverflow.com/questions/26921227/…
  • 感谢您对 Kampai 的评论!我认为所有内存都被正确释放。我在分析器中找不到泄漏或过多的内存消耗。那是真正困扰我的部分。 :(
  • 我猜想消耗更多内存的原因是nested for 结构。尝试以块方式或在后台重新格式化它。我不确定GPUImageFilter 内存结构——它也可能使用缓存。
  • for 循环在 1-3 个过滤器之间创建,它们被链接在一起。不应该完全破坏内存。我添加了自动释放池,以便在每个帧处理后释放内存。
  • AFAIK GPUImageFilter 不应被缓存。即使是,它也应该在内存压力下释放?

标签: ios iphone image-processing memory-management gpuimage


【解决方案1】:

让我印象深刻的一件事是,您正在为每个传入的帧创建一个新图像和一组新过滤器。这将非常低效,并且可能会使 GPUImage 中的内部帧缓冲区缓存系统过载。

相反,从 GPUImage 纹理输入开始创建过滤器链。分配过滤器一次,只需在每个新帧上更改它们的属性。对于输入,如果您将核心图像输出渲染到由纹理支持的 OpenGL ES 上下文中,然后将该纹理输入到 GPUImage 中,您将避免使用极其昂贵(内存和性能方面)的 GPU->CPU- >GPU 路径并将所有内容保留在 GPU 上。

过滤器创建一次并为每个帧重复使用,内部帧缓冲区缓存机制应该能够将内存使用限制在一个恒定且相对较低的值。

由于这里的退化情况,确实可能存在泄漏(我不经常以这种频率构建和拆除过滤器,因此在解除分配中可能存在竞争条件),但试图重新设计以重用在任何情况下,过滤器都可能是更好的选择。

关于您报告的 20 MB 值,这很可能来自分配工具,它隐藏了 OpenGL ES 内存使用情况。而是查看内存监视器,以真正了解您的总应用程序内存使用情况。我敢打赌它会高很多。

【讨论】:

  • 非常感谢您的回答,布拉德!我更改了代码以在处理开始时创建过滤器链。 (400 帧左右)不幸的是,结果相同。 (我仔细检查了过滤器只创建了一次!)我没有实施您使用GPUImageTextureInput 的建议,因为我目前不知道输入图像的纹理 ID。我的印象是 AVFoundation 直接将视频帧加载到帧缓冲区?我对目前的性能很满意,但是GPUImagePicture 的使用会成为内存错误的来源吗?
  • 我对 Apple/iOS 开发有点陌生,找不到内存监视器工具?是不是可能停产了?活动监视器显示“实际内存使用情况”,如果我理解正确,它应该显示 CPU 和 GPU 内存消耗。应用程序在崩溃之前仍有大约 20MB。
  • @Senad - 如果在将视频帧发送到 GPUImage 之前不需要通过 Core Image 进行处理,则可以改用 GPUImageVideoCamera 并从中获取像素缓冲区并将其交给并行到核心图像。看起来您正在使用面部特征检测,如果这就是您所需要的,这将运作良好。 FilterShowcase 示例有一个如何做到这一点的示例。
  • 另外,如果我将视频分辨率降低 100 像素进行测试,我可以处理视频,但在接近尾声时会收到很多内存警告。处理下一个视频时,我得到相同的结果。因此,这不是永久性的内存分配/泄漏,而是在处理期间快速累积。您的想法和 cmets 将不胜感激!! :)
  • @Senad - 关于内存监视器,看起来它已合并到活动监视器中。这使您可以准确地读取实际内存大小。如果您想随着时间的推移对其进行审查,您可能需要让它跟踪检查头以在应用程序执行的特定时间点进行监控。
【解决方案2】:
- (void)addObservers {
    [[NSNotificationCenter defaultCenter]addObserver:self
                                        selector:@selector(applicationDidEnterBackground:)
                                            name:UIApplicationDidEnterBackgroundNotification
                                          object:nil];

    [[NSNotificationCenter defaultCenter]addObserver:self
                                        selector:@selector(applicationDidBecomeActive:)
                                            name:UIApplicationDidBecomeActiveNotification
                                          object:nil];
}

- (void)removeObservers {
    [[NSNotificationCenter defaultCenter]removeObserver:self
                                               name:UIApplicationDidEnterBackgroundNotification
                                             object:nil];

    [[NSNotificationCenter defaultCenter]removeObserver:self
                                               name:UIApplicationDidBecomeActiveNotification
                                             object:nil];
}

【讨论】:

  • 对不起,这个答案似乎与问题无关
猜你喜欢
  • 1970-01-01
  • 2015-07-10
  • 1970-01-01
  • 2014-01-14
  • 1970-01-01
  • 2017-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多