8

Il seguente codice occuperà ~ 410 MB di memoria e non lo rilascerà. (La versione che utilizza dispatch_sync invece di dispatch_async richiede una memoria di ~ 8 MB)
Mi aspetto un picco di utilizzo della memoria elevato, ma dovrebbe ridiscendere ... Dov'è la perdita?GCD dispatch_async perdita di memoria?

int main(int argc, const char * argv[]) { 
    @autoreleasepool { 
    for (int i = 0; i < 100000; i++) { 
     dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ 
     NSLog(@"test"); 
     }); 
    } 
    NSLog(@"Waiting."); 
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]]; 
    } 
    return 0; 
} 

Ho provato:

  • Aggiunta @autoreleasepool intorno e all'interno del ciclo
  • Aggiunta NSRunLoop run all'anello

Ho provato varie combinazioni e mai visto una diminuzione di memoria (anche dopo aver atteso i minuti). Sono consapevole della guida di riferimento GCD che contiene la seguente dichiarazione:

Anche se GCD code di spedizione hanno le loro piscine autorelease, fanno nessuna garanzia in merito a quando le piscine sono drenate.

C'è una perdita di memoria in questo codice? In caso contrario, c'è un modo per far rispettare la coda per rilasciare/svuotare i blocchi finiti?

risposta

1

Objective-C block è una struttura in C, penso che si creino 100000 oggetti di blocco per eseguirli in thread in background e si aspettino che il sistema li possa eseguire. Il tuo dispositivo può eseguire un numero limitato di thread, significa che molti blocchi attenderanno prima che il sistema operativo li avvii.

Se si modifica "async" in "sync", verrà creato un blocco successivo dopo che un blocco precedente sarà terminato e distrutto.

UPD

Chi GCD piscina.

GCD esegue attività sul pool di thread GCD, i thread vengono creati dal sistema e gestiti dal sistema. Il sistema memorizza nella cache i thread per risparmiare tempo CPU, ogni attività di spedizione viene eseguita su thread libero.

Da documentazione:

-

blocchi inviati alle code di spedizione vengono eseguiti su un pool di thread completamente gestiti dal sistema. Non viene fornita alcuna garanzia sul thread su cui viene eseguita un'attività.

-

Se si esegue i compiti come compiti sincronizzati, allora esiste il filo libera (da GCD pool di thread) per eseguire attività successiva, dopo aver finito (perché thread principale di attività corrente è in attesa mentre il compito di eseguire, e non aggiunge nuove attività alla coda), e il sistema non assegna nuovo NSThread (Sul mio Mac ho visto 2 thread). Se si eseguono le attività come asincrone, il sistema può allocare molti NSThread (per ottenere le massime prestazioni, sul mio Mac è vicino a 67 thread), perché la coda globale contiene molte attività.

Here è possibile leggere il conteggio massimo del pool di thread GCD.

Ho visto in Alocations Profiler che ci sono molti NSThread assegnati e non distrutti. Penso che sia un pool di sistema, che verrà liberato se necessario.

+0

Questo è vero ma non è una risposta alla domanda. L'utilizzo della memoria dovrebbe ridursi (almeno) dopo che tutti i blocchi sono terminati. Ma non è questo il caso. Un picco di utilizzo della memoria alta andrebbe perfettamente bene. – Andreas

+0

Ho modificato la mia risposta. –

0

Metti sempre @autoreleasepool all'interno di ogni chiamata GCD e non avrai problemi. Ho avuto lo stesso problema e questa è l'unica soluzione.

int main(int argc, const char * argv[]) { 
    @autoreleasepool { 
    for (int i = 0; i < 100000; i++) { 
     dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{ 
     // everything INSIDE in an @autoreleasepool 
     @autoreleasepool { 
      NSLog(@"test"); 
     } 
     }); 
    } 
    NSLog(@"Waiting."); 
    [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:60]]; 
    } 
    return 0; 
}