Domanda

Ho un'applicazione che viene eseguito in background unico (specificando LSBackgroundOnly nel file Info.plist). Il problema è che tutti i blocchi che corro sulle code parallele non vengono rilasciate. Il codice viene eseguito in un ambiente di memoria gestiti -. Non è coinvolto GC

L'aspetto (semplificato) codice come qui di seguito. Grasso è solo una classe fittizio che contiene un NSDate per il test. Inoltre, sovrascrive retain, release, e dealloc a fare un po 'di registrazione:

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];

Se cambio l'applicazione di una normale applicazione (cioè non-sfondo), posso osservare i blocchi di essere rilasciato quando un ingresso è effettuata tramite l'interfaccia utente (anche cambiando lo stato attivo a un'altra finestra è sufficiente). Dal momento che il mio backgorund applicazione riceve in ingresso direttamente sopra il driver USB HID e non avere una finestra o un menu bar questo non accade.

C'è un modo per forzare manualmente il runloop o qualsiasi altra cosa è responsabile per raccontare le code per rilasciare i blocchi finiti?

(Tutti gli altri oggetti che erano stati trattenuti dai blocchi non sono anche rilasciato, creando enormi perdite di memoria. Queste perdite non possono essere spottet dalle perdite o ObjectAllocations strumenti, ma il consumo di memoria può essere osservato alle stelle con alto.)

È stato utile?

Soluzione

Un comune "Gotcha" per le piscine autorelease è che se l'applicazione sta costruendo memoria senza eventi che ricevono, il esterno piscina (quello gestito dal ciclo di eventi) non sarà drenante.

Non credo che si dovrebbe applicare qui dal momento che si sta gestendo la propria piscina ... ma solo nel caso, si potrebbe provare questo:

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

Altri suggerimenti

Sembra che si sta utilizzando un blocco basato pila che viene utilizzato dopo che il blocco va di portata. Il blocco deve essere copiato. Il codice dovrebbe funzionare se viene modificato in questo modo:

[concurrentQueue addOperationWithBlock:[[^{       
    NSAutoreleasePool *blockPool = [[NSAutoreleasePool alloc] init];
    NSDate *test = [aBlubber aDate];
    NSLog(@"Block DONE");
    [blockPool release];    
}copy]autorelease]];

Date un'occhiata a questo post per un interessante resoconto completo su blocchi: http://gkoreman.com/blog/2011/02/27/blocks-in-c-and-objective-c/

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top