一位用户报告说,我的应用程序冻结了,他必须强制退出。应用程序不会崩溃,它只是挂起。他给我发送了文件和条件,但我无法在我的计算机上重现挂起。他给我发了一个很长的崩溃日志,但问题似乎是在CGContextDrawPath期间发生的。下面是
17 CGContextDrawPath + 199(CoreGraphics + 323893)[0x7fff515da135] 1 - 17
17 ripc_DrawPath + 318(CoreGraphics + 324473)[0x7fff515da379] 1 - 17
17 ripc_Render + 381(CoreGraphics + 99778)[0x7fff515a35c2] 1 - 17
17 RIPRenderCoverage + 1639(CoreGraphics + 101667)[0x7fff515a3d23] 1 - 17
17 aa_render + 632(CoreGraphics + 559938)[0x7fff51613b42] 1 - 17
1 aa_distribute_edges + 436(CoreGraphics + 404181)[0x7fff515edad5](running) 1
2 aa_distribute_edges + 302(CoreGraphics + 404047)[0x7fff515eda4f](running) 2 - 3
1 aa_distribute_edges + 436(CoreGraphics + 404181)[0x7fff515edad5](running) 4
5 aa_distribute_edges + 302(CoreGraphics + 404047)[0x7fff515eda4f](running) 5 - 9
1 aa_distribute_edges + 436(CoreGraphics + 404181)[0x7fff515edad5](running) 10
3 aa_distribute_edges + 302(CoreGraphics + 404047)[0x7fff515eda4f](running) 11 - 13
2 aa_distribute_edges + 436(CoreGraphics + 404181)[0x7fff515edad5](running) 14 - 15
1 aa_distribute_edges + 302(CoreGraphics + 404047)[0x7fff515eda4f](running) 16
1 aa_distribute_edges + 436(CoreGraphics + 404181)[0x7fff515edad5](running) 17发生这种情况的例程是绘制一个图,路径只是点之间的线。用户告诉我,对于点数较少的图,这个问题就解决了。挂起应用程序的曲线图有60,000或更多的点。我给他发送了一个版本,在代码中的不同位置写入日志文件,似乎冻结发生在CGContextDrawPath内部。到达该行代码后,日志中不会出现任何内容。如果不能访问他的电脑我就不知道怎么调试了。任何人都有任何建议。我有其余的崩溃(挂起)日志,如果有帮助的话。
更新:2019年8月12日虽然我不能在我的macbook上重现这个“挂起”,但我确实安装了Xcode,并在我妻子的macbook上运行了这个项目,并且可以在xcode中重现这个“挂起”。导致挂起的代码是
CGPathRef path = CreatePath();
if(path) {
CGContextAddPath(context, path);
CFRelease(path);
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, foreColor.CGColor);
CGContextSetLineWidth(context,0.75);
CGContextDrawPath(context, kCGPathStroke);
CGContextRestoreGState(context);
return true;
}CreatePath()函数是一个MoveTo,后面跟着一个LineTo循环。我使用了CGPathApply并打印出了整个元素列表,每个元素都是我所期望的,即MoveTo后面跟着一堆LineTo。
代码在CGContextDrawPath中挂起,当我在Xcode中暂停应用程序时,它总是在"aa_distribute_edges“中。
我不仅不能弄清楚是什么导致了挂起,我也不知道为什么相同的代码没有挂在我的笔记本电脑上就可以工作。
更新:2019年8月13日仍然卡住。在两台计算机上运行Xcode,我可以一步一步地进入汇编代码,并遵循相同的应用程序,将相同的文档步骤完全相同地绘制到RIPRenderCoverage中。但是在这个例程中,没有挂起的计算机不会进入aa_render,而挂起的计算机会进入aa_render。一旦进入aa_render,挂起的计算机就进入aa_distribute_edges,然后似乎进入了一个无限循环。
天哪,我被难住了。非常需要这里的任何建议。
更新:2019年8月13日(下午)。我刚刚发现,如果我减少行宽,即CGContextSetLineWidth(context,0.5),而不是上面使用的行宽,就可以避免挂起。我对Core Graphics有什么不理解的地方?
更新时间:2019年8月19日。我发现挂起取决于所使用的显示器。具体地说,视网膜显示挂起。如果我将NSHighResolutionCapable添加到应用程序的info.plist中并将其设置为NO,那么这个问题就解决了,我可以使用任何线宽。因此,我的代码中的某些东西在高分辨率下绘制是错误的。
更新时间:2019年8月24日。我确实让它“挂”了一个多小时,但它从未在高分辨率模式下完成。在NSHighResolutionCapable关闭的情况下,相同的绘制是即时的(几毫秒)。如果我在每个点上画一个小圆圈,而不是用线连接,我也会在NSHighResolutionCapable上遇到一个挂起的问题。
更新时间:2019年9月6日。关闭NSHighResolutionCapable使我的应用程序不会在视网膜显示屏上崩溃,但用户抱怨说,视网膜显示屏上的窗口现在看起来有点模糊。
发布于 2019-08-24 09:00:57
我认为Core Graphics正在遭受严重的透支
此答案是根据您在问题中提供的证据进行的推测。
我相信这个挂起是一个很长的挂起,但不是完全的on deadlock,基于类似的report I read with poor plotting performance in the R language on macOS。
假设你的问题是类似的,那么如果你让它运行很长时间,它最终会渲染。
在CoreGraphics/Quartz2D中,我认为绘图发生在CPU上。也就是说,我无法从Apple's current docs上找到关于核心图形使用中央处理器还是图形处理器的明确信息,但有一些old information说,只有名为Quartz Extreme的旧技术才允许在核心图形中使用图形处理器渲染,但默认情况下是禁用的。由于挂起在一个名为ripc_Render的函数中,因此看起来它确实在CPU上呈现这些行。
由于Core Graphics的源代码不可用来检查,我不得不猜测,但我认为发生了什么:
CGContextAddLineToPoint时,它会将一个新点追加到一个点数组中。到目前为止,这项工作是关于points.CGContextDrawPath发送数据到CoreGraphics CPU渲染器的数量的线性O(n),它本质上是渲染位图图像。绘制线条所需的功是大于n(点数)的函数,也是线条宽度、屏幕密度和线条长度的函数。这就是为什么减少线条宽度或在非视网膜屏幕上运行可以提高performance.的原因
解决方案:减少积分
4K显示器的分辨率为3840x2160 (WxH)。如果您正在绘制一个function (在数学意义上,意味着所有的X值都是唯一的),那么您只能在4K监视器上显示3840个没有重叠的点。
一旦您的点数超过了屏幕上可以容纳的点数,就可以通过减少对CGContextAddLineToPoint的调用来消除一些路径点。您可以使用以下(未经测试的) puedo-code算法之一,其中DP[]是您的数据点数组,WxH是以像素为单位的屏幕分辨率。
跳过:如果为DP.length > W,则仅绘制每个数据point
DP.length > W,则仅绘制(DP.length/W)数据点如果为DP.length > W,则绘制W数据点,其中每个条形图是每个数据点points.
DP.length/W的平均值:如果为DP.length > W,则在每组<代码>D30数据点中的最小和最大Y值之间画一条垂直线。无论使用哪种算法,都会对绘制的线条数量设置一个上限,这应该会显着减少在CGContextDrawPath中花费的时间。
https://stackoverflow.com/questions/57453758
复制相似问题