我有一个为macOS 10.11+构建的应用程序。此应用需要运行一些可能偶尔崩溃的第三方代码(The Libsass compiler)。为了避免关闭我的整个应用程序,我已经创建了一个运行此代码的XPC服务(使用NSXPCConnection
和Xcode中的标准XPC服务模板)。
XPC服务似乎是将运行我的代码的线程的堆栈大小设置为512kb
,这是线程其他的macOS默认值而不是主线程。 (默认情况下,主线程的堆栈大小为8MB
。)
Libsass编译器有时会因涉及深度递归的某些文件(以及许多堆栈帧)的堆栈溢出而崩溃。
NB:我知道这是问题,因为如果我在我应用的主线程上运行完全相同的Libsass序列(不使用XPC),那么一切工作正常,堆栈溢出永远不会发生。
增加我的XPC服务执行工作的线程的堆栈大小的方法。
我已将-Wl,-stack_size,4000000
添加到"其他链接器标记"为我的XPC服务目标构建设置。这将堆栈大小设置为64MB(允许的最大值)。构建之后,我检查Finder中的XPC包,并使用此命令验证链接器是否正确应用了此标志:
otool -lV codekit-libsass-service.xpc/Contents/MacOS/codekit-libsass-service | grep stack
产生此输出:stacksize 67108864
,表示堆栈大小确实已设置为64MB
。
问题是这只适用于服务的主线程,而我的XPC方法似乎没有在服务的主线程上调用。我使用[NSThread isMainThread]
验证了这一点,在我的XPC方法中调用时返回false
。
所以,我尝试强制使用dispatch_async(dispatch_get_main_queue() ^{...});
在主线程上完成工作但是,-isMainThread
仍然从返回false
那块。此外,如果我使用[NSThread currentThread] stackSize]
,我会得到524288
,这表示运行此代码的线程具有512kb
堆栈。奇妙。
我还尝试使用setrlimit()
在运行时动态提高堆栈大小。这并没有解决问题。
我已经阅读了很多文档。 XPC服务使用的线程的具体细节以及它们如何使用它们似乎是我们不应该担心的实现细节。
答案 0 :(得分:0)
虽然有效,但我无法想象它是最好的方法。基本上,如果您有这样的XPC方法:
- (void) doStuffWithObject:(NSDictionary *)dict withReply:(void (^)(NSString *))reply
{
// Code that needs a bigger stack.
}
然后你可以这样做:
- (void) doStuffWithObject:(NSDictionary *)dict withReply:(void (^)(NSString *))reply
{
NSThread *thread = [[NSThread alloc] initWithBlock:
^{
// Code that needs a bigger stack
}];
[thread setStackSize:67108864]; // 64MB. Must be in multiples of 4096.
[thread start];
}
每次调用此方法时都会设置一个线程,但这是(到目前为止)我想到的增加堆栈大小的唯一方法。
任何人都有更好的方法吗?