8

Der folgende Code belegt ca. 410 MB Arbeitsspeicher und gibt ihn nicht wieder frei. (Die Version mit dispatch_sync anstelle von dispatch_async wird ~ 8MB Speicher benötigen)
Ich würde eine Spitze von hoher Speicherauslastung erwarten, aber es sollte wieder sinken ... Wo ist das Leck?GCD dispatch_async Speicherleck?

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

Ich habe versucht:

  • Hinzufügen @autoreleasepool um und innerhalb der Schleife
  • NSRunLoop run an die Schleife Hinzufügen

ich verschiedene Kombinationen ausprobiert und nie eine Abnahme des Gedächtnisses sah (sogar nach dem Warten Minuten). Ich bin mir bewusst, der GCD-Referenzhandbuch, das die folgende Erklärung enthält:

Obwohl GCD Dispatch-Warteschlangen ihre eigenen Autofreigabepools haben, machen sie keine Garantie, wenn diese Pools abgelassen werden.

Gibt es in diesem Code ein Speicherleck? Wenn nicht, gibt es eine Möglichkeit, die Warteschlange zu erzwingen, um die fertigen Blöcke freizugeben/zu leeren?

Antwort

1

Objective-C-Block es ist eine C-Struktur, ich denke, Sie erstellen 100000 die Blockobjekte, um sie in Hintergrundthreads auszuführen und sie warten, während System sie ausführen kann. Ihr Gerät kann eine begrenzte Anzahl von Threads ausführen. Dies bedeutet, dass viele Blöcke warten, bevor das Betriebssystem sie startet.

Wenn Sie "async" in "sync" ändern, wird ein nächstes Blockobjekt erstellt, nachdem ein vorhergehender Block beendet und zerstört wurde.

UPD

Über Pool GCD.

GCD führt Aufgaben im GCD-Threadpool aus, Threads werden vom System erstellt und vom System verwaltet. Das System speichert Threads zwischen, um CPU-Zeit zu sparen. Jeder Dispatch-Task wird im freien Thread ausgeführt.

Aus Dokumentation:

-

Blöcke vorgelegt Versand Warteschlangen auf einem Pool von Threads durch das System vollständig verwalteten ausgeführt werden. Es wird keine Garantie für den Thread gegeben, auf dem eine Aufgabe ausgeführt wird.

-

Wenn Sie die Aufgaben als synchronisierte Aufgaben ausführen, existieren dann das freie Gewinde (von GCD-Thread-Pool) nächste Aufgabe auszuführen, nachdem beendet die aktuelle Aufgabe (weil Haupt-Thread wartet, während Aufgabe auszuführen, und Fügt der Warteschlange keine neuen Aufgaben hinzu und das System weist keinen neuen NSThread zu (Auf meinem Mac habe ich 2 Threads gesehen). Wenn Sie die Tasks als async ausführen, kann das System viele NSThreads zuweisen (um maximale Leistung zu erreichen, befinden sich auf meinem Mac fast 67 Threads), da die globale Warteschlange viele Tasks enthält.

Here können Sie über maximale Anzahl der GCD-Thread-Pool lesen.

Ich habe in Alocations Profiler gesehen, dass es viele NSThreads zugeordnet und nicht zerstört. Ich denke, es ist ein Systempool, der bei Bedarf freigegeben wird.

+0

Das stimmt, aber keine Antwort auf die Frage. Die Speicherauslastung sollte (mindestens) nach dem Ende aller Blöcke wieder sinken. Aber das ist hier nicht der Fall. Ein Spitzenwert von hohem Speicherverbrauch wäre völlig in Ordnung. – Andreas

+0

Ich habe meine Antwort bearbeitet. –

0

Setzen Sie @autoreleasepool immer in jeden GCD-Aufruf und Sie werden keine Probleme haben. Ich hatte das gleiche Problem und das ist die einzige Problemumgehung.

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