前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS图像处理系列 - GPUImage源码解读(二)

iOS图像处理系列 - GPUImage源码解读(二)

作者头像
天天P图攻城狮
发布2018-02-02 15:51:48
2.9K0
发布2018-02-02 15:51:48
举报

导语 :billzbwang写的《iOS 图像处理系列 - GPUImage源码解读(一)》里详细地介绍了核心代码的具体实现,对GPUImage的使用者有很大的参考价值。在GPUImage中,有一个不为大多数人所注意却又极其重要的模块GPUImageFramebufferCache。在《iOS 图像处理系列 - GPUImage源码解读》系列的第二篇中,我就把自己对这一模块粗浅的了解分享给大家。

GPUImageFramebufferCache这个类主要的作用是对GPUImageFramebuffer的管理。这个类对外暴露了如下5个接口。

其中我们主要使用fetchFramebufferForSize的两个方法。

我们一般会在制作自定义滤镜时用到这个类,在GPUImageFilter的使用这个类时,会在- (void)renderToTextureWithVertices:textureCoordinates:中以如下的形式获取一个GPUImageFramebuffer。

outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];

在获取一个分framebuffer后,我们会调用framebuffer的lock方法加锁以防Framebuffer回收,使用完毕后再调用unlock解锁。在GPUImageFramebuffer类的内部,则使用了一个名为framebufferReferenceCount的变量做引用计数,为0时调用GPUImageFramebufferCache的returnFramebufferToCache方法告知GPUImageFramebufferCache回收framebuffer。

由此,我们可以看到,GPUImage为我们提供了一套完善的framebuffer的cache机制,从GPUImageContext的sharedFramebufferCache里取一个framebuffer,当没有人使用时再自动还回Cache。

那么问题来了,我们为什么要用cache里的framebuffer呢?自己创建一个,使用完后再释放行不行呢?

答案显示是NO。

我们来看一下GPUImageFramebuffer类的代码,在dealloc中,调用了destroyFramebuffer方法,这个方法的实现如下。

问题就出在其中的renderTarget上,当创建GPUImageFramebuffer时给onlyTexture参数填NO(一般就是填NO的)时,会创建一个CVPixelBufferRef类型的变量renderTarget,当用CFRelease去释放这个变量时,它占用的内存并不会立即释放,而是要调用

CVOpenGLESTextureCacheFlush([[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache], 0);

之后,才会真正释放内存。这个现象的原因可以在GPUImageFrameBuffer的init函数中找到。

其中coreVideoTextureCache是CVOpenGLESTextureCacheRef类型的属性,也就是说,renderTarget的内存,并不是自己创建的,而是来自OpenGLESTextureCache,在调用CFRelease时也不会自行释放。如果不知道其中的原理,自行创建GPUImageFramebuffer,dealloc时并没有真正释放内存,会造成内存泄漏,而且每次都是一帧视频或者一幅图像的大小,相当可观。

而在GPUImageFramebufferCache的purgeAllUnassignedFramebuffers方法中,会帮我们清空OpenGLESTextureCache,真正释放GPUImageFramebuffer占用内存。purgeAllUnassignedFramebuffers方法会在收到memory warning时触发释放内存,一般情况下无需自行调用。

所以,GPUImage给我们实现了一套完善的framebuffer的cache机制,如果不用它而是自行创建和管理framebuffer去处理视频和大量图片时,稍有不慎就会出现crash的情况。在这种情况下出现的crash并不会抛出异常,在xcode提供的内存检测工具中也不能观测到内存增长,会让不明就里的人难以定位crash的原因。

下面让我们看一下GPUImageFramebufferCache的实现。GPUImageFramebufferCache通过以下方法去获取一个cache里的GPUImageFramebuffer。

而其中的hashForSize:textureOptions:onlyTexture:方法如下。

可以看出,当framebuffer的size和textureOptions、onlyTexture相同时,GPUImageFramebufferCache优先从cache中拿一个已有的framebuffer出来,在没有的情况下则创建一个新的。

我们在处理视频时,处理每帧时都会申请framebuffer,从而造成连续申请GPUImageFramebuffer,而这样申请到的framebuffer一般是从GPUImageFramebufferCache中拿到的已经使用过的,如果在使用时为了追求效率不对每个点赋值可能出现所谓的“灵异问题”。

总结一下,我们在使用GPUImageFramebuffer时,要注意两点,一是通过GPUImageFramebufferCache获取framebuffer,以免出现内存没有释放的问题;二是从Cache中获取framebuffer后,要注意framebuffer里的脏数据造成的问题。


作者简介:ygdai(戴阳刚),天天P图iOS工程师

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-06-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 天天P图攻城狮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
检测工具
域名服务检测工具(Detection Tools)提供了全面的智能化域名诊断,包括Whois、DNS生效等特性检测,同时提供SSL证书相关特性检测,保障您的域名和网站健康。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档