Gibt es eine Möglichkeit herauszufinden, wo meine App einen ANR (Application Not Responding) ausgegeben hat? Ich habe mir die Datei traces.txt in /data angesehen und sehe einen Trace für meine Anwendung. Das sehe ich im Trace.
DALVIK THREADS:
"main" prio=5 tid=3 TIMED_WAIT
| group="main" sCount=1 dsCount=0 s=0 obj=0x400143a8
| sysTid=691 nice=0 sched=0/0 handle=-1091117924
at java.lang.Object.wait(Native Method)
- waiting on <0x1cd570> (a android.os.MessageQueue)
at java.lang.Object.wait(Object.java:195)
at android.os.MessageQueue.next(MessageQueue.java:144)
at android.os.Looper.loop(Looper.java:110)
at android.app.ActivityThread.main(ActivityThread.java:3742)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
at dalvik.system.NativeStart.main(Native Method)
"Binder Thread #3" prio=5 tid=15 NATIVE
| group="main" sCount=1 dsCount=0 s=0 obj=0x434e7758
| sysTid=734 nice=0 sched=0/0 handle=1733632
at dalvik.system.NativeStart.run(Native Method)
"Binder Thread #2" prio=5 tid=13 NATIVE
| group="main" sCount=1 dsCount=0 s=0 obj=0x433af808
| sysTid=696 nice=0 sched=0/0 handle=1369840
at dalvik.system.NativeStart.run(Native Method)
"Binder Thread #1" prio=5 tid=11 NATIVE
| group="main" sCount=1 dsCount=0 s=0 obj=0x433aca10
| sysTid=695 nice=0 sched=0/0 handle=1367448
at dalvik.system.NativeStart.run(Native Method)
"JDWP" daemon prio=5 tid=9 VMWAIT
| group="system" sCount=1 dsCount=0 s=0 obj=0x433ac2a0
| sysTid=694 nice=0 sched=0/0 handle=1367136
at dalvik.system.NativeStart.run(Native Method)
"Signal Catcher" daemon prio=5 tid=7 RUNNABLE
| group="system" sCount=0 dsCount=0 s=0 obj=0x433ac1e8
| sysTid=693 nice=0 sched=0/0 handle=1366712
at dalvik.system.NativeStart.run(Native Method)
"HeapWorker" daemon prio=5 tid=5 VMWAIT
| group="system" sCount=1 dsCount=0 s=0 obj=0x4253ef88
| sysTid=692 nice=0 sched=0/0 handle=1366472
at dalvik.system.NativeStart.run(Native Method)
----- end 691 -----
Wie kann ich herausfinden, wo das Problem liegt? Die Methoden im Trace sind alle SDK-Methoden.
Ich habe einen Bericht dieser Art, der auch bei passiert android.os.MessageQueue.nativePollOnce(Native Method). Kann ich es bedenkenlos ignorieren?
– rts
20. Juni 2012 um 12:00 Uhr
Ein ANR tritt auf, wenn im “Haupt”-Thread eine lange Operation stattfindet. Dies ist der Thread der Ereignisschleife, und wenn er beschäftigt ist, kann Android keine weiteren GUI-Ereignisse in der Anwendung verarbeiten und wirft daher einen ANR-Dialog aus.
Nun, in der von Ihnen geposteten Ablaufverfolgung scheint der Hauptthread gut zu funktionieren, es gibt kein Problem. Es befindet sich im Leerlauf in der MessageQueue und wartet auf das Eintreffen einer weiteren Nachricht. In Ihrem Fall war die ANR wahrscheinlich eine längere Operation und nicht etwas, das den Thread dauerhaft blockierte, sodass der Ereignis-Thread nach Abschluss der Operation wiederhergestellt wurde und Ihre Ablaufverfolgung durchlief nach ANR.
Es ist einfach zu erkennen, wo ANRs auftreten, wenn es sich um eine dauerhafte Blockierung handelt (z. B. ein Deadlock, der einige Sperren erwirbt), aber schwieriger, wenn es sich nur um eine vorübergehende Verzögerung handelt. Gehen Sie zuerst Ihren Code durch und suchen Sie nach Schwachstellen und lang andauernden Vorgängen. Beispiele können die Verwendung von Sockets, Sperren, Thread-Ruhezuständen und anderen Blockierungsvorgängen innerhalb des Ereignis-Threads umfassen. Sie sollten sicherstellen, dass dies alles in separaten Threads geschieht. Wenn nichts das Problem zu sein scheint, verwenden Sie DDMS und aktivieren Sie die Thread-Ansicht. Dies zeigt alle Threads in Ihrer Anwendung ähnlich der Ablaufverfolgung, die Sie haben. Reproduzieren Sie die ANR und aktualisieren Sie gleichzeitig den Hauptthread. Das sollte Ihnen genau zeigen, was zur Zeit des ANR vor sich ging
Das einzige Problem ist “ANR reproduzieren” 🙂 . Könnten Sie bitte erklären, wie der Hauptthread dieser Stack-Trace-Show “im Leerlauf” ist, das wäre großartig.
– Blundell
30. März 2011 um 11:53 Uhr
Der Stack-Trace zeigt, dass sich der Haupt-Thread im Looper (der Nachrichtenschleifenimplementierung) befindet und eine zeitgesteuerte Wartezeit durch Object.wait durchführt. Dies bedeutet, dass die Nachrichtenschleife derzeit keine Nachrichten zu versenden hat und auf den Eingang neuer Nachrichten wartet. Ein ANR tritt auf, wenn das System erkennt, dass eine Nachrichtenschleife zu viel Zeit mit der Verarbeitung einer Nachricht und nicht mit der Verarbeitung anderer Nachrichten in der Schleife verbringt Warteschlange. Wenn die Schleife auf Nachrichten wartet, geschieht dies offensichtlich nicht.
– bald
31. März 2011 um 18:25 Uhr
@Soonil Hallo, wissen Sie, was der Rest der Abschnitte bedeutet, wie z. Außerdem enthält es Informationen wie VMWAIT, RUNNABLE, NATIVE
– minhaz
27. Februar 2012 um 19:39 Uhr
Meine App ist NDK-basiert, ich sehe das gleiche ANR. Auch der Hauptfaden ist in Ordnung. Ich habe DDMS ausprobiert und meinen Worker-Thread aktualisiert, wenn er einfriert. Leider bekomme ich nur eine einzige Zeile NativeStart::run. Ist die DDMS-Threadansicht überhaupt in der Lage, native NDK-Threads zu inspizieren? Außerdem: StrictMode hat nichts gefunden.
Sie können aktivieren Strikter Modus in API-Level 9 und höher.
StrictMode wird am häufigsten verwendet, um versehentliche Festplatten- oder Netzwerkzugriffe im Hauptthread der Anwendung abzufangen, wo UI-Vorgänge empfangen und Animationen stattfinden. Indem Sie den Haupt-Thread Ihrer Anwendung reaktionsfähig halten, tun Sie das auch ANR-Dialoge verhindern Benutzern nicht angezeigt werden.
verwenden penaltyLog() Sie können die Ausgabe von adb logcat beobachten, während Sie Ihre Anwendung verwenden, um die Verstöße zu sehen, während sie auftreten.
StrictMode kann nicht in einen Typ aufgelöst werden. Muss ich vorher etwas importieren? Das Drücken von STRG+UMSCHALT+O hilft nicht.
– kuchi
24. Januar 2012 um 4:41 Uhr
Kleiner Tipp – verwenden Sie if (BuildConfig.DEBUG) … um die Aufnahme in die Produktion zu verhindern
– Amir Uwal
14. November 2013 um 14:12 Uhr
@uval was meinst du mit “um die Aufnahme in die Produktion zu verhindern” ?!!
– Muhammed Refaat
1. April 2015 um 13:49 Uhr
@MuhammedRefaat es verhindert keine ANR. Es stürzt die App sofort statt nach 5 Sekunden ab. Wenn Sie beispielsweise im Hauptthread auf die Datenbank zugreifen und es 2 Sekunden dauert, erhalten Sie kein ANR, aber StrictMode stürzt die App ab. StrictMode ist ausschließlich für Ihre Debugging-Phase, nicht für die Produktion.
– Amir Uwal
2. April 2015 um 11:31 Uhr
@MuhammedRefaat hat meine Antwort auf Ihre Frage hinzugefügt.
– Amir Uwal
4. April 2015 um 9:37 Uhr
Sie fragen sich, welche Aufgabe einen UI-Thread enthält. Trace-Datei gibt Ihnen einen Hinweis, um die Aufgabe zu finden. Sie müssen den Status jedes Threads untersuchen
Zustand des Threads
running – Ausführen von Anwendungscode
schlafend – genannt Thread.sleep()
monitor – wartet darauf, eine Monitorsperre zu erwerben
warte – in Object.wait()
native – Ausführen von nativem Code
vmwait – Warten auf eine VM-Ressource
Zombie – Thread ist im Begriff zu sterben
init – Thread wird initialisiert (Sie sollten dies nicht sehen)
Starting – Thread beginnt gleich (sollten Sie auch nicht sehen)
Konzentrieren Sie sich auf den Zustand SUSPENDED, MONITOR. Der Überwachungsstatus gibt an, welcher Thread untersucht wird, und der Status SUSPENDED des Threads ist wahrscheinlich der Hauptgrund für Deadlocks.
Grundlegende Untersuchungsschritte
Finden Sie “Warten auf Sperre”
Sie können den Monitorstatus finden “Binder Thread #15” prio=5 tid=75 MONITOR
Sie haben Glück, wenn Sie “waiting to lock” finden
Beispiel: Warten auf Sperren von <0xblahblah> (ein com.foo.A), das von threadid=74 gehalten wird
Sie können feststellen, dass “tid=74” jetzt eine Aufgabe enthält. Gehen Sie also zu tid=74
Trace enthält nicht immer “waiting to lock”. In diesem Fall ist es schwierig, den Hauptgrund zu finden.
Schöne Erklärung. Jetzt ist es für mich einfacher, ANR-Protokolle zu verstehen. Aber ich habe immer noch ein Problem zu verstehen, weil ich in Schritt 1 die Thread-ID leicht finden kann, aber wenn ich in Schritt 2 versuche, dorthin zu gehen, wo sie ist, um den Status zu überprüfen, kann ich sie nicht finden . Irgendeine Idee, wie es weitergeht?
– THZ
23. November 2018 um 14:09 Uhr
Ich habe - waiting to lock an unknown object Innerhalb "HeapTaskDaemon" daemon prio=5 tid=8 Blocked . Was bedeutet kann jemand helfen?
– Hilal
10. Dezember 2019 um 13:44 Uhr
Ich habe in den letzten Monaten Android gelernt, bin also weit davon entfernt, ein Experte zu sein, aber ich war wirklich enttäuscht von der Dokumentation zu ANRs.
Die meisten Ratschläge scheinen darauf ausgerichtet zu sein, sie zu vermeiden oder zu beheben, indem Sie Ihren Code blind durchsehen, was großartig ist, aber ich konnte nichts zur Analyse der Ablaufverfolgung finden.
Es gibt drei Dinge, auf die Sie bei ANR-Protokollen wirklich achten müssen.
1) Deadlocks: Wenn sich ein Thread im WAIT-Zustand befindet, können Sie die Details durchsehen, um herauszufinden, von wem er „gehalten“ wird. Meistens wird es von selbst gehalten, aber wenn es von einem anderen Faden gehalten wird, ist das wahrscheinlich ein Gefahrenzeichen. Sehen Sie sich diesen Thread an und sehen Sie, was er hält. Möglicherweise finden Sie eine Schleife, die ein klares Zeichen dafür ist, dass etwas schief gelaufen ist. Das ist ziemlich selten, aber es ist der erste Punkt, denn wenn es passiert, ist es ein Albtraum
2) Haupt-Thread wartet: Wenn sich Ihr Haupt-Thread im WAIT-Zustand befindet, überprüfen Sie, ob er von einem anderen Thread gehalten wird. Dies sollte nicht passieren, da Ihr UI-Thread nicht von einem Hintergrundthread gehalten werden sollte.
Beide Szenarien bedeuten, dass Sie Ihren Code erheblich überarbeiten müssen.
3) Schwerwiegende Operationen im Hauptthread: Dies ist die häufigste Ursache für ANRs, aber manchmal eine der schwieriger zu findenden und zu behebenden. Sehen Sie sich die Details des Hauptthreads an. Scrollen Sie im Stack-Trace nach unten, bis Sie Klassen sehen, die Sie erkennen (aus Ihrer App). Sehen Sie sich die Methoden im Trace an und finden Sie heraus, ob Sie an diesen Stellen Netzwerkaufrufe, DB-Aufrufe usw. tätigen.
Schließlich, und ich entschuldige mich dafür, dass ich meinen eigenen Code schamlos eingefügt habe, können Sie den Python-Protokollanalysator verwenden, bei dem ich geschrieben habe https://github.com/HarshEvilGeek/Android-Log-Analyzer Dies durchsucht Ihre Protokolldateien, öffnet ANR-Dateien, findet Deadlocks, findet wartende Haupt-Threads, findet nicht erfasste Ausnahmen in Ihren Agentenprotokollen und druckt alles relativ leicht lesbar auf dem Bildschirm aus. Lesen Sie die ReadMe-Datei (die ich gleich hinzufügen werde), um zu erfahren, wie Sie sie verwenden. Es hat mir in der letzten Woche sehr geholfen!
Wann immer Sie Timing-Probleme analysieren, hilft das Debuggen oft nicht, da das Einfrieren der App an einem Haltepunkt das Problem verschwinden lässt.
Am besten fügen Sie viele Protokollierungsaufrufe (Log.XXX()) in die verschiedenen Threads und Rückrufe der App ein und sehen, wo die Verzögerung liegt. Wenn Sie einen Stacktrace benötigen, erstellen Sie eine neue Ausnahme (instanziieren Sie einfach eine) und protokollieren Sie sie.
Vielen Dank für den Hinweis zum Erstellen einer neuen Ausnahme, wenn Sie einen Stacktrace benötigen. Das ist sehr hilfreich beim Debuggen 🙂
– kuchi
24. Januar 2012 um 4:43 Uhr
Jack
Was löst ANR aus?
Im Allgemeinen zeigt das System eine ANR an, wenn eine Anwendung nicht auf Benutzereingaben reagieren kann.
In jeder Situation, in der Ihre App einen potenziell langwierigen Vorgang ausführt, sollten Sie die Arbeit nicht im UI-Thread ausführen, sondern stattdessen einen Worker-Thread erstellen und dort den größten Teil der Arbeit erledigen. Dies hält den UI-Thread (der die Ereignisschleife der Benutzeroberfläche steuert) am Laufen und verhindert, dass das System zu dem Schluss kommt, dass Ihr Code eingefroren ist.
Wie man ANRs vermeidet
Android-Anwendungen werden normalerweise vollständig auf einem einzigen Thread ausgeführt, standardmäßig dem „UI-Thread“ oder „Haupt-Thread“). Dies bedeutet, dass alles, was Ihre Anwendung im UI-Thread tut, was lange dauert, den ANR-Dialog auslösen kann, da Ihre Anwendung sich selbst keine Chance gibt, das Eingabeereignis oder die Intent-Broadcasts zu verarbeiten.
Daher sollte jede Methode, die im UI-Thread ausgeführt wird, in diesem Thread so wenig Arbeit wie möglich leisten. Insbesondere sollten Aktivitäten so wenig wie möglich in wichtigen Lebenszyklusmethoden wie onCreate() und onResume() eingerichtet werden. Potenziell lang andauernde Operationen wie Netzwerk- oder Datenbankoperationen oder rechenintensive Berechnungen wie die Größenänderung von Bitmaps sollten in einem Worker-Thread (oder im Fall von Datenbankoperationen über eine asynchrone Anforderung) durchgeführt werden.
Code: Worker-Thread mit der AsyncTask-Klasse
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
// Do the long-running work in here
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
// This is called each time you call publishProgress()
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
// This is called when doInBackground() is finished
protected void onPostExecute(Long result) {
showNotification("Downloaded " + result + " bytes");
}
}
Code: Worker-Thread ausführen
Um diesen Worker-Thread auszuführen, erstellen Sie einfach eine Instanz und rufen Sie execute() auf:
new DownloadFilesTask().execute(url1, url2, url3);
Ich habe einen Bericht dieser Art, der auch bei passiert
android.os.MessageQueue.nativePollOnce(Native Method)
. Kann ich es bedenkenlos ignorieren?– rts
20. Juni 2012 um 12:00 Uhr