Objective-C块未发布仅用于后台应用程序

时间:2010-08-25 12:07:06

标签: objective-c memory-leaks user-input objective-c-blocks background-application

我有一个仅在后台运行的应用程序(通过在info.plist文件中指定LSBackgroundOnly)。 问题是,我在并行队列上运行的所有块都没有被释放。 代码在内存管理环境中执行 - 不涉及GC。

(简化)代码如下所示。 Blubber只是一个虚拟类,持有NSDate进行测试。此外,它会覆盖retainreleasedealloc来执行一些日志记录:

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驱动程序接收输入,并且它没有窗口或菜单栏,因此不会发生这种情况。

有没有办法手动强制运行runloop或任何负责告诉队列释放已完成的块?

(块保留的所有其他对象也没有被释放,造成巨大的内存泄漏。这些泄漏不会被Leaks或ObjectAllocations工具发现,但是使用top可以观察到内存消耗暴涨。)

2 个答案:

答案 0 :(得分:2)

自动释放池的一个常见“问题”是,如果应用程序正在构建内存而不接收事件,则最外层池(由事件循环管理的池)将不会耗尽。< / p>

我不认为这应该适用于此,因为您正在管理自己的游泳池......但为了以防万一,您可以试试这个:

...
//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];
}

答案 1 :(得分:0)

看起来您正在使用在块超出范围后使用的基于堆栈的块。需要复制块。如果代码更改为此代码应该有效:

[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-objective-c/