30

Ich habe eine iOS-App in Swift geschrieben, die Speicher verliert - in bestimmten Situationen sollten einige Objekte veröffentlicht werden, aber sie sind nicht. Ich habe durch einfaches Hinzufügen von deinit Debug-Meldungen wie diese über das Thema gelernt:Wie kann man Speicherlecks beheben, wenn das Leaks-Instrument sie nicht anzeigt?

deinit { 
    println("DEINIT: KeysProvider released") 
} 

So sollte die deinit Meldung nach solchen Ereignissen in der Konsole vorhanden sein, die das Objekt führen soll zu lösen. Bei einigen Objekten, die freigegeben werden sollten, fehlt jedoch die Nachricht. Dennoch zeigt das Leaks Developer Tool keine Lecks. Wie löse ich eine solche Situation?

+0

ich bin nicht sicher das ist ein guter Test. Möglicherweise befindet sich irgendwo in Ihrem Code ein Zeiger auf diese Routinen. Oder der Swift-Compiler ist schlau genug, um 'deinit' aufzurufen, wenn er nicht benötigt wird. Sie benötigen einen besseren Test für ausgelaufenen Speicher. – zaph

Antwort

63

In Xcode 8 können Sie auf der "Debug-Speicher Graph" klicken, debugmemorygraphbutton in der Debug-Symbolleiste (am unteren Rand des Bildschirms angezeigt):

debug memory graph

Nur Identifizieren Sie das Objekt im linken Bereich, von dem Sie denken, dass es freigegeben werden sollte, und es zeigt Ihnen das Objektdiagramm (oben im Hauptfenster angezeigt). Dies ist sehr nützlich, um schnell zu erkennen, wo die starken Referenzen auf dem fraglichen Objekt festgestellt wurden. Von hier aus können Sie Ihre Nachforschungen beginnen und diagnostizieren, warum diese starken Referenzen nicht aufgelöst wurden (zB wenn das fragliche Objekt eine starke Referenz von etwas anderem hat, das hätte freigegeben werden sollen, schauen Sie sich auch das Diagramm dieses Objekts an, und Sie könnten das finden Problem (z. B. starke Referenzzyklen, Wiederholungstimer usw.)

Beachten Sie, dass im rechten Bereich der Anrufbaum angezeigt wird.Ich habe, dass in den Schema-Einstellungen auf dem „malloc Stack“ Protokollierungsoption durch Drehen:

malloc stack

Wie dem auch sei, das getan zu haben, kann man dann auf den Pfeil neben dem entsprechenden Call-Methode in dem Stapel gezeigt Spur auf der rechten Seite des ersten Siebes snapshot oben, und man kann sehen, dass eine starke Referenz wurde ursprünglich etabliert:

code

die obige Speicherdiagnosetechnik (und mehr) wird in der zweiten Hälfte des WWDC demonstrierte 2016 Visual Debugging with Xcode.

Die traditionelle Instrumente Technik (besonders nützlich, wenn Sie ältere Versionen von Xcode verwenden) wird in meiner ursprünglichen Antwort unten beschrieben.


Ich würde mit dem "Belegungen" Werkzeug Instruments vorschlagen "Record Reference Counts" -Funktion:

record reference counts

Anschließend können Sie die App in Instruments laufen und dann für Ihre Klasse suchen, Sie wissen, ist undicht und bohren in indem Sie auf den Pfeil klicken:

enter image description here

Sie können dann bohren in die Details und Blick auf die Stack-Trace „Erweiterte Details“ Panel auf der rechten Seite:

extended details

In diesem „Erweiterte Details“ Panel, konzentrieren sich auf den Code in schwarz, anstatt das System ruft in grau. Wie auch immer, von der „Erweiterte Details“ Panel können Sie dann in Ihren Quellcode bohren, rechts in Instrumente ::

your code

Weitere Informationen und Demonstrationen in Instrumente mit Gedächtnisproblemen auf die Spur finden Sie auf :

+0

Danke. Die von Ihnen vorgeschlagene Vorgehensweise ist wahrscheinlich die beste Verwendung von Instrumenten zur Erkennung starker Zyklen. Das ist jedoch immer noch nicht sehr nützlich. Ich kann sehen, was die Referenzzahl für bestimmte Klassen im Moment ist, aber was ich wirklich brauchen würde ist, welche Objekte diese Referenzen halten ... Aber das ist ein schlechtes Design von Instrumenten, Ihre Antwort ist großartig. Vielen Dank! – drasto

+0

Es zeigt nicht nur, was die Referenzzahl ist, sondern, was noch wichtiger ist, es zeigt Ihnen, wo diese starken Referenzen etabliert wurden. Ich habe einen starken Referenzzyklus als Beispiel genommen, aber es funktioniert mit jedem Besitz-Szenario. – Rob

+0

Ja, aber es zeigt mir, wo ** alle ** starken Referenzen durch die Geschichte des Objekts festgestellt wurden. Bei einem typischen Programmablauf, bei dem viele Referenzen beibehalten und freigegeben werden, ist das nahezu nutzlos.Ich bin nur an unveröffentlichten starken Referenzen interessiert und ich bekomme nur ihre Zählung: wie viele von ihnen gibt es im Moment (Nummer in RefCt Spalte in der letzten Reihe). Alle diese beibehaltenen und dann veröffentlichten Referenzen spenden nur den Tisch für mich. Zu viele Informationen ohne die Fähigkeit, die Teile zu finden, die ich wirklich brauche, sind normalerweise dieselben wie keine Informationen. – drasto

2

Verwenden Sie Instrumente zur Überprüfung auf Lecks und Speicherverlust aufgrund von beibehaltenem, aber nicht ausgelaufenem Speicher. Letzteres ist ungenutzter Speicher, auf den immer noch hingewiesen wird. Verwenden Sie im Zuweisungsinstrument für Instrumente die Markengenerierung (Heapshot).

Für HowTo Verwendung Heapshot Speicher creap zu finden, siehe: bbum blog

Grundsätzlich ist das Verfahren Instruments zuweisen Werkzeug, nehmen Sie einen heapshot, führen eine Iteration des Codes und einen weiteren heapshot Wiederholung 3 oder 4 mal laufen. Dies zeigt Speicher an, der während der Iterationen zugewiesen und nicht freigegeben wurde.

Um herauszufinden, die Ergebnisse offenbaren, um die einzelnen Zuordnungen zu sehen.

Wenn Sie sehen müssen, wo behält, Releases und autoreleases auftreten für ein Objekt verwenden, Instrumente:

Run in Instrumente, in Verrechnungen eingestellt „Record Referenzzähler“ auf (für Xcode 5 und senken Sie die Aufnahme stoppen um die Option zu setzen). Führen Sie die App aus, beenden Sie die Aufzeichnung, führen Sie einen Drilldown durch und Sie werden sehen können, wo alle Änderungen, Freigaben und Autoreleases aufgetreten sind.