Question

J'ai une application qui fonctionne seulement en arrière-plan (en spécifiant LSBackgroundOnly dans le fichier Info.plist). Le problème est que tous les blocs que je cours sur les files d'attente parallèles ne sont pas libérés. Le code est exécuté dans un environnement géré mémoire -. GC ne participe

Le look de code (simplifié) comme ci-dessous. Est juste une Blubber classe factice qui est titulaire d'un NSDate pour les tests. , Elle écrasera aussi retain, release et dealloc faire une exploitation forestière:

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 je change l'application à une application normale (à savoir la non-backgound), je peux observer les blocs libérés chaque fois qu'une entrée est effectuée par l'intermédiaire de l'interface utilisateur (même de changer la mise au point vers une autre fenêtre est suffisante). Depuis mon application backgorund reçoit une entrée directement au-dessus du pilote USB HID et il ne dispose pas d'une fenêtre ou la barre de menus, cela ne se produit pas.

Est-il possible de forcer manuellement le runloop ou tout ce qui est responsable de dire les files d'attente pour libérer les blocs finis?

(Tous les autres objets qui avaient été retenus par les blocs ne sont pas non libérés, créant d'énormes fuites de mémoire. Ces fuites ne peuvent pas être spottet par les outils Fuites ou ObjectAllocations, mais la consommation de mémoire peut être observé la montée en flèche en utilisant le dessus.)

Était-ce utile?

La solution

Une commune pour les piscines autorelease « gotcha » est que si l'application est la construction de la mémoire sans recevoir des événements, la plus externe piscine (celui géré par la boucle d'événement) ne sera pas la vidange.

Je ne pense pas que cela devrait appliquer ici puisque vous gérez votre propre piscine ... mais juste au cas où, vous pouvez essayer ceci:

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

Autres conseils

Il semble que vous utilisez une pile bloc à base qui est utilisé après que le bloc est passé hors de portée. Le bloc doit être copié. Le code devrait fonctionner si elle est modifiée à ceci:

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

Jetez un oeil à ce poste pour un writeup complet sur des blocs: http://gkoreman.com/blog/2011/02/27/blocks-in-c-and-objective-c/

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top