MacOS 10.15:设计速度慢

2020-05-22 23:56:20

在ATP的第379集中,Marco Arment和John Siracusa都描述了升级到MacOS10.15后明显的延误和停滞。

我自己一直在努力解决这个问题,我发现了几个可能导致这些延迟的系统操作,我将在下面详细说明。

解决延迟的一种方法是禁用您的互联网连接。这是一种难治的良药,但如果您注意到这些延迟,请尝试一小时,以验证是否确实通过禁用互联网连接解决了问题。

另一种减少延迟的方法是禁用系统完整性保护。我说减少,因为即使在禁用SIP的情况下,我仍然会遇到一些延迟,但系统总体感觉要快得多,我强烈建议任何认为他们的系统速度慢的人也这样做。

苹果公司引入了公证,撇开这给我们开发人员带来的不便不谈,这也导致了用户体验的降级,因为用户第一次运行新的可执行文件时,苹果会在等待服务器回复的同时延迟执行。这张支票给我花了将近一秒钟的时间。

这不仅仅是从互联网上下载的文件,也不仅仅是当你通过Finder启动它们的时候,这就是一切。因此,即使您编写了一行shell脚本并在终端中运行它,您也会得到延迟!

老实说,这简直令人费解。苹果是否将我所有自定义脚本的源代码发送到他们的服务器?考虑到他们在隐私方面的立场,我不这么认为,所以他们很可能只是发送了一个校验和,但是他们在做什么,系统在本地不能做的校验和呢?

至于公证检查,结果是缓存的,所以第二次调用应该很快,但如果您是开发人员,您可能会定期更新脚本和二进制文件,这会触发新的检查(缓存似乎基于inode,因此就地更新保存可能会避免触发新的检查),或者您的工作流可能涉及动态创建和执行脚本,这一性能现在取决于Apple服务器的响应能力。

这个问题我见过的最严重的延迟大约是7秒,我有几集似乎没有缓存结果,所以重复发射仍然会有延迟。

此问题已报告给Apple并分配给FB7674490。然而,苹果回应说,这是“设计出来的”(这篇文章的标题也因此而来)。

Apple有几个文件系统位置需要用户权限才能访问,例如~/桌面、~/文档和~/下载。

然而,令人惊讶的是,仅仅是获得其中一个文件夹的显示名称或图标就会触发苹果的代码,以验证客户端是否允许访问该位置。

这是通过向沙盒进程发送一条消息来实现的,该进程向tccd发送一条消息,tccd调用SecCodeCheckValidityWithErrors并似乎与另一个进程通信,但我找不到是哪个进程,每个位置大约需要150毫秒。

此延迟是针对访问的每个特权位置的,虽然缓存了结果,但缓存仅持续到应用程序的下一次重新启动。

为了重现这段视频,我打开了“传输”,然后转到“首选项”“→Transfer”。在这里您可以配置3个不同的文件夹,它们显示在带有名称和图标的弹出按钮中。我将它们配置为~/桌面、~/文档和~/下载。在我的系统上重新启动传输和打开首选项导致了0.62秒的延迟(相当明显)。

堆栈的相关部分(在此延迟期间)是-[NSWorkspace iconForFile:]→getattrlist→__WAITING_ON_APPROVAL_FROM_SANDBOXD__。

但是,再说一次,有些地方不对劲。特别是调用SecKeychainFindGenericPassword可能会导致明显的延迟,在一个糟糕的互联网日子里,我让这个调用暂停了3.3秒,这是在系统完整性保护被禁用的情况下!

然而,禁用互联网消除了延迟。在启用互联网的情况下,它可以通过重新启动应用程序并触发名为SecKeychainFindGenericPassword的代码来重现。

此问题已报告给Apple并分配给FB7679198。苹果回应说,应用程序不应该使用这个函数,尽管SecKeychainFindGenericPassword的文档没有说明它已被弃用,即使它被弃用,当已经被授予访问钥匙链项的应用程序请求此项时,它仍然不应该造成数秒的延迟。

在我的系统上,创建一个ABAddressBook实例平均需要0.3秒,但我已经让它占用了1秒以上的时间。

就像使用密钥链访问一样,如果禁用互联网,问题就会完全消除,但禁用SIP时就不会了。

不过,大多数情况下都是在启动应用程序时。在启动期间对应用程序进行采样会显示ImageLoaderMachO::loadCodeSignature、SLSMainConnectionID中的停顿,以及堆栈跟踪中对Skylight和CGS的许多引用。

所有上述问题都是在新的Mac mini上遇到的,操作系统故意保持尽可能接近“出厂默认”,我从一个朋友(他在他的机器上运行测试)那里得到了上面一些问题的确认,尽管他的时间与我的不同,但他们都显示出上面确定的操作明显延迟。

我写这篇文章是为了引起人们注意我认为苹果最新操作系统存在的一个严重的设计问题,在这些问题中,低级系统API(如exec和getxattr)现在似乎在返回调用者之前执行同步网络活动。

在启用SIP的情况下,在糟糕的互联网日,我可以让整台机器每10分钟冻结1-2秒,更不用说一切都很慢了。