Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/9.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
Multithreading 如何防止NSBitmapImageRep创建大量中间CGImage?_Multithreading_Macos_Cgimage_Nsbitmapimagerep - Fatal编程技术网

Multithreading 如何防止NSBitmapImageRep创建大量中间CGImage?

Multithreading 如何防止NSBitmapImageRep创建大量中间CGImage?,multithreading,macos,cgimage,nsbitmapimagerep,Multithreading,Macos,Cgimage,Nsbitmapimagerep,我有一个生成性的艺术应用程序,它从一小部分点开始,向外扩展,并检查增长以确保它不与任何东西相交。我的第一个天真的实现是在主UI线程上完成这一切,并产生预期的结果。随着大小的增长,需要检查的点越来越多,速度会减慢,最终会阻塞UI 我做了一件显而易见的事情,并将计算转移到另一个线程,以便UI能够保持响应。这有帮助,但只是一点点。为此,我使用了一个NSBitmapImageRep,将NSGraphicsContext包裹起来,这样我就可以在其中进行绘制。但是我需要确保我没有试图在主UI线程上将其绘制到

我有一个生成性的艺术应用程序,它从一小部分点开始,向外扩展,并检查增长以确保它不与任何东西相交。我的第一个天真的实现是在主UI线程上完成这一切,并产生预期的结果。随着大小的增长,需要检查的点越来越多,速度会减慢,最终会阻塞UI

我做了一件显而易见的事情,并将计算转移到另一个线程,以便UI能够保持响应。这有帮助,但只是一点点。为此,我使用了一个
NSBitmapImageRep
,将
NSGraphicsContext
包裹起来,这样我就可以在其中进行绘制。但是我需要确保我没有试图在主UI线程上将其绘制到屏幕上,同时我也在后台线程上绘制它。所以我引进了一把锁。由于数据越来越大,绘图可能需要很长时间,因此即使这样也有问题

我的最新版本有2个
NSBitmapImageRep
s。其中一个保存最近绘制的版本,并在视图需要更新时绘制到屏幕上。另一个被绘制到背景线程上。背景线程上的绘图完成后,将复制到另一个线程。我通过获取每个像素的基址并简单地调用
memcpy()
将像素从一个移动到另一个来进行复制。(我尝试交换它们,而不是复制,但即使绘图以调用
[-NSGraphicsContext flushContext]
结束,我还是得到了部分绘制到窗口的结果。)

计算线程如下所示:

    BOOL    done    = NO;
    while (!done)
    {
        self->model->lockBranches();
        self->model->iterate();
        done = (!self->model->moreToDivide()) || (!self->keepIterating);
        self->model->unlockBranches();

        [self drawIntoOffscreen];

        dispatch_async(dispatch_get_main_queue(), ^{
            self.needsDisplay = YES;
        });
    }
NSBItmapImageRep *bitmapIGotFromAPIThatDidNotSpecifyFormat;
NSBitmapImageRep *bitmapWhoseFormatIKnow = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:width pixelsHigh:height
                                                  bitsPerSample:bps samplesPerPixel:spp hasAlpha:alpha isPlanar:isPlanar
                                                  colorSpaceName:colorSpaceName bitmapFormat:bitmapFormat bytesPerRow:rowBytes
                                                  bitsPerPixel:pixelBits];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmapWhoseFormatIKnow]];
[bitmapIGotFromAPIThatDidNotSpecifyFormat draw];
[NSGraphicsContext restoreGraphicsState];
unsigned char *bitmapDataIUnderstand = [bitmapWhoseFormatIKnow bitmapData];
这足以保持UI的响应性。但是,每次我将绘制的图像复制到blitting图像中时,我都会调用
[-NSBitmapImageRep baseAddress]
。查看instruments中的内存配置文件,每次调用该函数都会创建一个
CGImage
。此外,在计算完成之前,
CGImage
不会发布,这可能需要几分钟。这会导致内存变得相当大。在我的过程中,我看到了大约3-4个CG图像,尽管我从来都不需要超过2个。在计算完成并清空缓存后,我的应用程序的内存将降至350-500 MB。我没有想过在计算循环中使用自动释放池来实现这一点,但我会尝试一下


操作系统似乎正在缓存它创建的映像。但是,在计算完成之前,它不会清除缓存,因此在计算完成之前,它将不受限制地增长。有什么方法可以防止这种情况发生吗?

不要使用
-bitmapData
memcpy()
复制图像。将一个图像绘制到另一个图像中

我经常建议开发人员阅读以下网站中的“NSBitmapImageRep:CoreGraphics阻抗匹配和性能说明”一节:

NSBitmapImageRep:CoreGraphics阻抗匹配和性能说明 上面的发行说明详细说明了NSImage级别的核心更改 雪豹。在这方面也有实质性的变化 NSBitmapImageRep级别,也用于性能和改善阻抗 与CoreGraphics匹配

NSImage是一种相当抽象的图像表示。很漂亮 这只是一个可以画画的东西,尽管它没有NSView那么抽象 在这方面,它的行为不应基于上下文的不同方面 除了质量决策之外,它还被纳入了其他领域。那是一种不透明的颜色 语句,但可以用一个例子来说明:如果你画一个 按钮插入100x22区域与22x22区域,您可以预期 按钮以拉伸其中部,但不拉伸其端盖。图像不应 这样做(如果你尝试,你可能会崩溃!)。形象 应始终线性且均匀地缩放以填充其中的矩形 虽然它可能会选择表示等来优化 该地区的质量。类似地,中的所有图像表示形式 NSImage应表示相同的图形。不要完全打包 不同的形象在作为代表

这一离题已经过去,NSBitmapImageRep是一个更具体的概念 对象NSImage没有像素,NSBitmapImageRep有像素。一 NSBitmapImageRep是一组数据和像素格式 信息和色彩空间信息,使我们能够解释 数据作为颜色值的矩形数组

这和CGImage差不多。雪豹 NSBitmapImageRep本机由CGImageRef支持,而不是 直接创建一块数据。CGImageRef确实拥有数据块。 在Leopard中,从CGImage实例化的NSBitmapImageRep将 解包并可能处理数据(从 位图文件格式),在SnowLeopard中,我们努力保持 原始图像

这会对性能产生一些影响。大多数都很好!你应该看到 减少了位图数据作为CG图像的编码和解码。如果你 从JPEG文件初始化NSImage,然后将其绘制为PDF,然后 应获得与原始JPEG文件大小相同的PDF文件。在里面 Leopard你会看到一个PDF大小的解压缩图像。接受 另一个例子是CoreGraphics缓存,包括上传到 图形卡,都绑定到CGImage实例,所以越是相同 实例可以更好地使用

然而,在某种程度上,快速的操作 NSBitmapImageRep已更改。CGI图像是不可变的, NSBitmapImageRep是。如果修改NSBitmapImageRep,请在内部修改它 可能需要从CGImage中复制数据,并将 更改,并将其重新打包为新的CGImage。所以,基本上,绘画 NSBitmapImageRep速度很快,查看或修改其像素数据非常困难 不这在豹子身上是真实的,但现在更真实了

上述步骤确实是惰性的:如果你做了导致 NSBitmapImageRep t