3

バックグラウンドでのみ実行されるアプリケーションがあります ( LSBackgroundOnlyinfo.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 ドライバーを介して直接入力を受け取り、ウィンドウやメニュー バーがないため、これは発生しません。

実行ループを手動で強制する方法や、完成したブロックを解放するようにキューに指示する責任があるものはありますか?

(ブロックによって保持されていた他のすべてのオブジェクトも解放されず、大量のメモリ リークが発生します。これらのリークは、Leaks ツールまたは ObjectAllocations ツールでは検出できませんが、top を使用するとメモリ消費が急増することが観察できます。)

4

2 に答える 2

2

自動解放プールの一般的な "落とし穴" の 1 つは、アプリがイベントを受信せずにメモリを構築している場合、最も外側のプール (イベント ループによって管理されるプール) が排出されないことです。

あなたは自分のプールを管理しているので、ここでは当てはまらないと思います...しかし、念のため、これを試すことができます:

...
//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];
}
于 2011-01-27T08:21:46.030 に答える
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/

于 2011-02-27T22:36:08.067 に答える