XPC 服务:增加工作线程上的堆栈大小
XPC Service: Raise Stack Size on Worker Thread
背景语境:
我有一个为 macOS 10.11+ 构建的应用程序。此应用程序需要 运行 一些可能偶尔会崩溃的第三方代码 (The Libsass compiler)。为避免关闭我的整个应用程序,我创建了一个 XPC 服务(使用 NSXPCConnection
和 Xcode 中的标准 XPC 服务模板)运行 是此代码。
我的问题:
XPC 服务似乎正在将 运行 我的代码所在的线程的堆栈大小设置为 512kb
,这是线程的 macOS 默认值 other 比主线程。 (主线程的堆栈大小默认为8MB
。)
Libsass 编译器有时会在某些涉及深度递归(因此有许多堆栈帧)的文件上因堆栈溢出而崩溃。
注意: 我知道这是问题所在,因为如果我 运行 完全 相同的 Libsass 序列在我的应用程序的主线程(不使用 XPC),一切正常,堆栈溢出永远不会发生。
我需要什么:
一种增加我的 XPC 服务执行工作的线程堆栈大小的方法。
我尝试过的:
我已经将 -Wl,-stack_size,4000000
添加到我的 XPC 服务目标的 "other linker flags" 构建设置中。这会将堆栈大小设置为 64MB(允许的最大值)。构建后,我在 Finder 中检查 XPC 包,并使用以下命令验证链接器是否正确应用了此标志:
otool -lV codekit-libsass-service.xpc/Contents/MacOS/codekit-libsass-service | grep stack
产生此输出:stacksize 67108864
,表明堆栈大小确实已设置为 64MB
。
麻烦的是,这仅适用于服务的 main 线程,而我的 XPC 方法似乎并未在服务的主线程上调用。我通过使用 [NSThread isMainThread]
验证了这一点,在我的 XPC 方法中调用时 returns false
。
所以,然后我尝试 强制 使用 dispatch_async(dispatch_get_main_queue() ^{...});
在主线程上完成工作但是,-isMainThread
仍然 returns false
来自 在 该块内。而且,如果我使用[NSThread currentThread] stackSize]
,我得到524288
,这表明这段代码所在的线程运行ning有一个512kb
堆栈。太棒了。
我还尝试使用 setrlimit()
在 运行 时动态增加堆栈大小。这没有解决问题。
我已经阅读了很多文档。 XPC 服务使用哪些线程以及它们如何使用它们的细节似乎是我们不应该担心的实现细节。
虽然有效,但我无法想象这是最好的方法。基本上,如果您有这样的 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];
}
每次调用此方法时设置线程都会产生开销,但这是(到目前为止)我能想到的增加堆栈大小的唯一方法。
谁有更好的方法?
背景语境:
我有一个为 macOS 10.11+ 构建的应用程序。此应用程序需要 运行 一些可能偶尔会崩溃的第三方代码 (The Libsass compiler)。为避免关闭我的整个应用程序,我创建了一个 XPC 服务(使用 NSXPCConnection
和 Xcode 中的标准 XPC 服务模板)运行 是此代码。
我的问题:
XPC 服务似乎正在将 运行 我的代码所在的线程的堆栈大小设置为 512kb
,这是线程的 macOS 默认值 other 比主线程。 (主线程的堆栈大小默认为8MB
。)
Libsass 编译器有时会在某些涉及深度递归(因此有许多堆栈帧)的文件上因堆栈溢出而崩溃。
注意: 我知道这是问题所在,因为如果我 运行 完全 相同的 Libsass 序列在我的应用程序的主线程(不使用 XPC),一切正常,堆栈溢出永远不会发生。
我需要什么:
一种增加我的 XPC 服务执行工作的线程堆栈大小的方法。
我尝试过的:
我已经将 -Wl,-stack_size,4000000
添加到我的 XPC 服务目标的 "other linker flags" 构建设置中。这会将堆栈大小设置为 64MB(允许的最大值)。构建后,我在 Finder 中检查 XPC 包,并使用以下命令验证链接器是否正确应用了此标志:
otool -lV codekit-libsass-service.xpc/Contents/MacOS/codekit-libsass-service | grep stack
产生此输出:stacksize 67108864
,表明堆栈大小确实已设置为 64MB
。
麻烦的是,这仅适用于服务的 main 线程,而我的 XPC 方法似乎并未在服务的主线程上调用。我通过使用 [NSThread isMainThread]
验证了这一点,在我的 XPC 方法中调用时 returns false
。
所以,然后我尝试 强制 使用 dispatch_async(dispatch_get_main_queue() ^{...});
在主线程上完成工作但是,-isMainThread
仍然 returns false
来自 在 该块内。而且,如果我使用[NSThread currentThread] stackSize]
,我得到524288
,这表明这段代码所在的线程运行ning有一个512kb
堆栈。太棒了。
我还尝试使用 setrlimit()
在 运行 时动态增加堆栈大小。这没有解决问题。
我已经阅读了很多文档。 XPC 服务使用哪些线程以及它们如何使用它们的细节似乎是我们不应该担心的实现细节。
虽然有效,但我无法想象这是最好的方法。基本上,如果您有这样的 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];
}
每次调用此方法时设置线程都会产生开销,但这是(到目前为止)我能想到的增加堆栈大小的唯一方法。
谁有更好的方法?