Objective-C块未发布仅用于背景应用程序
题
我有一个仅在后台运行的应用程序(通过指定 LSBackgroundOnly
在info.plist文件中)。问题是,我在并行队列上运行的所有块都没有释放。该代码在内存管理的环境中执行 - 不涉及GC。
(简化的)代码如下所示。 Blubber只是一些虚拟级别,可容纳NSDATE进行测试。另外,它覆盖了 retain
, release
, , 和 dealloc
进行一些记录:
NSOperationQueue *concurrentQueue = [[NSOperationQueue alloc] init];
[concurrentQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];
Blubber *aBlubber = [[Blubber alloc] init];
aBlubber.aDate = [NSDate date];
[concurrentQueue addOperationWithBlock:^{
NSAutoreleasePool *blockPool = [[NSAutoreleasePool alloc] init];
NSDate *test = [aBlubber aDate];
NSLog(@"Block DONE");
[blockPool release];
}];
[aBlubber release];
[concurrentQueue release];
如果将应用程序更改为正常的(即非背心)应用程序,则可以在通过UI进行任何输入时观察释放的块(即使将焦点更改为另一个窗口也足够)。由于我的Backgorund应用程序直接在HID USB驱动程序上接收输入,并且它没有窗口或菜单栏,这不会发生。
是否有任何方法可以手动强制奔跑环或任何负责告诉队列释放成品块的负责人?
(也没有释放由块保留的所有其他对象,会产生巨大的内存泄漏。这些泄漏无法通过泄漏或抛弃工具发现这些泄漏,但是可以使用TOP观察到内存消耗。)
解决方案
Autorelease池的一个常见“陷阱”是,如果该应用程序正在构建内存而没有收到事件,则 最外面 泳池(由活动循环管理的一个)不会耗尽。
我认为这不应该在这里适用,因为您要管理自己的池...但是以防万一,您可以尝试以下操作:
...
//When no events are coming in (i.e. the user is away from their computer), the runloop doesn't iterate, and we accumulate autoreleased objects
[[NSTimer scheduledTimerWithTimeInterval:60.0f target:self selector:@selector(kickRunLoop:) userInfo:nil repeats:YES] retain];
...
- (void) kickRunLoop:(NSTimer *)dummy
{
// Send a fake event to wake the loop up.
[NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
location:NSMakePoint(0,0)
modifierFlags:0
timestamp:0
windowNumber:0
context:NULL
subtype:0
data1:0
data2:0]
atStart:NO];
}
其他提示
看来您正在使用堆栈范围不在范围之后使用的基于堆栈的块。需要复制块。如果将代码更改为此:该代码应工作:
[concurrentQueue addOperationWithBlock:[[^{
NSAutoreleasePool *blockPool = [[NSAutoreleasePool alloc] init];
NSDate *test = [aBlubber aDate];
NSLog(@"Block DONE");
[blockPool release];
}copy]autorelease]];
看这篇文章,以在块上进行完整写: http://gkoreman.com/blog/2011/02/27/blocks-in-c-and-bobigntive-c/
不隶属于 StackOverflow