Pregunta

Tengo una aplicación que se ejecuta en segundo plano solamente (especificando LSBackgroundOnly en el archivo info.plist). El problema es, que todos los bloques que se ejecutan en las colas paralelas no están siendo liberados. El código se ejecuta en un entorno de memoria gestionados -. No GC está involucrado

Las miradas (simplificado) código como abajo. Grasa es sólo una clase ficticia que tiene una NSDate para la prueba. Asimismo, se sobrescribe retain, release y dealloc que hacer algún registro:

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

Si cambio la aplicación para ser una aplicación normal (es decir, no backgound), puedo observar los bloques de ser liberado cuando cualquier entrada se realiza a través de la interfaz de usuario (incluso cambiando el enfoque a otra ventana es suficiente). Desde mi aplicación backgorund recibe la entrada directamente sobre el conductor USB HID y no tener una ventana o menú de la barra que esto no suceda.

¿Hay alguna manera de forzar manualmente el runloop o lo que es responsable de decirle a las colas para liberar los bloques terminados?

(Todos los demás objetos que habían sido retenidos por los bloques tampoco son liberados, creando enormes pérdidas de memoria. Estas fugas no pueden ser spottet por las fugas o ObjectAllocations herramientas, pero el consumo de memoria pueden ser observados por las nubes usando la parte superior.)

¿Fue útil?

Solución

Uno común "Gotcha" para piscinas autorelease es que si la aplicación es la construcción de la memoria sin recibir eventos, el más externa de la piscina (el gestionado por el bucle de eventos) no ser agotador.

No creo que debería aplicarse aquí, ya que está la gestión de su propia piscina ... pero por si acaso, se podría intentar esto:

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

Otros consejos

Parece que está utilizando un bloque basado en pila que se utiliza después de que el bloque ha ido fuera de alcance. El bloque debe copiarse. El código debería funcionar si se cambia a esto:

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

Tome un vistazo a este post para una valoración crítica completa en bloques: http://gkoreman.com/blog/2011/02/27/blocks-in-c-and-objective-c/

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top