if(!_imageContext) _imageContext = [self contextOfSize:imageSize];
代替:
CGContextRef imageContext = [self contextOfSize:imageSize];
当然,我不再发布CGContext了。
这些是我做出的唯一的改变,结果是重用上下文将渲染速度从10ms延迟到60ms。我错过了什么吗?在再次绘制之前,我必须清除上下文吗?还是重新创建每个图像的上下文的正确方法?
编辑
找到最奇怪的连接..
当我在搜索应用程序的内存在应用程序开始渲染图像时令人难以置信的原因,我发现问题是我将渲染的图像设置为NSImageView。
imageView.image = nil; imageView.image = [[NSImage alloc] initWithCGImage:_imageRef size:size];
看起来ARC并没有释放以前的NSImage。第一种避免这种情况的方法是将新的形象画成旧的形象。
[imageView.image lockFocus]; [[[NSImage alloc] initWithCGImage:_imageRef size:size] drawInRect:NSMakeRect(0,size.width,size.height) fromrect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; [imageView.image unlockFocus]; [imageView setNeedsdisplay];
内存问题已经消失,CGContext重用问题发生了什么?
不重用上下文现在需要20ms而不是10ms – 当然,绘制图像比仅仅设置它更长。
重用上下文也需要20ms而不是60ms。但为什么?我看不到有任何连接,但是我可以通过设置NSImageView的图像而不是绘制它来再现旧的状态,重复使用需要更多的时间。
解决方法
Running Time Self Symbol Name 668.0ms 32.3% 668.0 __bzero 668.0ms 32.3% 0.0 vm_fault 668.0ms 32.3% 0.0 user_trap 668.0ms 32.3% 0.0 CGSColorMaskcopyARGB8888_sse
这是通过CGSColorMaskcopyARGB8888_sse访问它们而导致内存归零的内存页面。这意味着CGContext将VM页面映射到位图上下文,但内核实际上并没有执行与该操作相关联的工作,直到有人实际访问该内存。实际的映射/故障发生在第一次访问。
现在我们来看看最重的内核跟踪,当我们重用上下文时:
Running Time Self Symbol Name 1327.0ms 35.0% 1327.0 bcopy 1327.0ms 35.0% 0.0 user_trap 1327.0ms 35.0% 0.0 CGSColorMaskcopyARGB8888_sse
这是内核复制页面。我的钱将是这样的底层写作机制,提供@RyanArtecona在他的评论中所谈论的行为:
In the Apple docs for CGBitmapContextCreateImage,it says the actual
bit-copying operation doesn’t happen until more drawing is done on the
original context.
在设计的情况下,我曾经测试过,非重用案例执行了3392ms,重用案例花费了4693ms(明显慢)。考虑到每种情况下只有单一最重的踪迹,内核跟踪表明我们在第一次访问时花费668.0ms零填充新页面,在图像获取参考后,首次写入时写入写入页上的页面为1327.0ms到那些页面。这是659ms的差异。两者之间的差距仅占这两个差距的50%。
所以,为了减少一点,非重用的上下文更快,因为当您创建上下文时,它知道这些页面是空的,并且没有其他人引用这些页面来强制它们在写入时被复制他们。当您重复使用上下文时,页面由其他人(您创建的映像)引用,并且必须在第一次写入时复制,以便在上下文的状态更改时保留映像的状态。
您可以通过在调试器中逐步查看进程的虚拟内存映射来进一步探索这里发生的情况。 vmmap是有用的工具。
实际上,您应该每次都可以创建一个新的CGContext。