Czy istnieje sposób na sprawdzenie, gdzie moja aplikacja zgłosiła błąd ANR (aplikacja nie odpowiada)? Rzuciłem okiem na plik traces.txt w / data i widzę ślad dla mojej aplikacji. Oto, co widzę w śladzie.
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 -----
Jak mogę się dowiedzieć, gdzie jest problem? Wszystkie metody śledzenia są metodami zestawu SDK.
Dzięki.
android
performance
android-anr-dialog
lostInTransit
źródło
źródło
android.os.MessageQueue.nativePollOnce(Native Method)
. Czy mogę bezpiecznie to zignorować?Odpowiedzi:
Błąd ANR występuje, gdy w głównym wątku ma miejsce długa operacja. To jest wątek pętli zdarzeń, a jeśli jest zajęty, system Android nie może przetwarzać żadnych dalszych zdarzeń GUI w aplikacji i dlatego wyświetla okno dialogowe ANR.
Teraz, w opublikowanym śladzie, główny wątek wydaje się działać dobrze, nie ma problemu. Jest na biegu jałowym w MessageQueue, czekając na nadejście kolejnej wiadomości. W Twoim przypadku błąd ANR był prawdopodobnie dłuższą operacją, a nie czymś, co trwale zablokowało wątek, więc wątek zdarzenia został odtworzony po zakończeniu operacji, a ślad przeszedł po ANR.
Wykrywanie, gdzie występują błędy ANR, jest łatwe, jeśli jest to trwała blokada (na przykład zakleszczenie w celu uzyskania niektórych blokad), ale trudniejsze, jeśli jest to tylko tymczasowe opóźnienie. Najpierw przejrzyj swój kod i poszukaj miejsc podlegających vunerowi i długotrwałych operacji. Przykłady mogą obejmować używanie gniazd, blokad, uśpień wątków i innych operacji blokujących z poziomu wątku zdarzeń. Powinieneś upewnić się, że wszystko to dzieje się w osobnych wątkach. Jeśli nic nie wydaje się problemem, użyj DDMS i włącz widok wątku. To pokazuje wszystkie wątki w twojej aplikacji podobne do śladu, który masz. Odtwórz błąd ANR i odśwież główny wątek w tym samym czasie. To powinno dokładnie pokazać, co się dzieje w czasie błędu ANR
źródło
Możesz włączyć StrictMode na poziomie API 9 i wyższym.
źródło
Zastanawiasz się, które zadanie zawiera wątek interfejsu użytkownika. Plik śledzenia daje wskazówkę, jak znaleźć zadanie. musisz zbadać stan każdego wątku
Stan wątku
Skoncentruj się na stanie ZAWIESZONY, MONITOROWY. Stan monitora wskazuje, który wątek jest badany, a stan ZAWIESZENIA wątku jest prawdopodobnie główną przyczyną zakleszczenia.
Podstawowe kroki badawcze
ślad nie zawsze zawiera „oczekiwanie na zablokowanie”. w tym przypadku trudno znaleźć główny powód.
źródło
- waiting to lock an unknown object
środku"HeapTaskDaemon" daemon prio=5 tid=8 Blocked
. Co to znaczy, czy ktoś może pomóc?Uczyłem się Androida przez ostatnie kilka miesięcy, więc daleko mi do eksperta, ale byłem bardzo rozczarowany dokumentacją dotyczącą błędów ANR.
Większość porad wydaje się być ukierunkowana na unikanie ich lub naprawianie przez ślepe przeglądanie kodu, co jest świetne, ale nie mogłem znaleźć nic na temat analizy śladu.
Są trzy rzeczy, których naprawdę musisz szukać w dziennikach ANR.
1) Zakleszczenia: Gdy wątek jest w stanie OCZEKIWANIA, możesz przejrzeć szczegóły, aby znaleźć osobę, która jest „holdby =”. Przez większość czasu będzie trzymany samodzielnie, ale jeśli jest trzymany przez inną nitkę, prawdopodobnie będzie to znak niebezpieczeństwa. Idź, spójrz na tę nić i zobacz, na czym ona polega. Możesz znaleźć pętlę, która jest wyraźnym znakiem, że coś poszło nie tak. Jest to dość rzadkie, ale to pierwsza kwestia, ponieważ kiedy to się dzieje, jest to koszmar
2) Główny wątek Oczekiwanie: Jeśli twój główny wątek jest w stanie WAIT, sprawdź, czy nie jest wstrzymany przez inny wątek. To nie powinno się zdarzyć, ponieważ Twój wątek interfejsu użytkownika nie powinien być utrzymywany przez wątek w tle.
Oba te scenariusze oznaczają, że musisz znacznie przerobić kod.
3) Ciężkie operacje w głównym wątku: jest to najczęstsza przyczyna błędów ANR, ale czasami jedna z trudniejszych do znalezienia i naprawienia. Spójrz na główne szczegóły wątku. Przewiń w dół ślad stosu, aż zobaczysz klasy, które rozpoznajesz (z Twojej aplikacji). Przyjrzyj się metodom śledzenia i dowiedz się, czy w tych miejscach wykonujesz połączenia sieciowe, wywołania bazy danych itp.
Na koniec przepraszam za bezwstydne podłączenie mojego własnego kodu, możesz skorzystać z analizatora dzienników Pythona, który napisałem na https://github.com/HarshEvilGeek/Android-Log-Analyzer To przejdzie przez twoje pliki dziennika, otwórz pliki ANR, znajdź zakleszczenia, znajdowanie oczekujących wątków głównych, znajdowanie nieprzechwyconych wyjątków w dziennikach agentów i drukowanie wszystkiego na ekranie w stosunkowo łatwy do odczytania sposób. Przeczytaj plik ReadMe (który za chwilę dodam), aby dowiedzieć się, jak go używać. Pomogło mi to w ostatnim tygodniu!
źródło
Ilekroć analizujesz problemy z synchronizacją, debugowanie często nie pomaga, ponieważ zawieszenie aplikacji w punkcie przerwania sprawi, że problem zniknie.
Najlepszym rozwiązaniem jest wstawienie wielu wywołań rejestrowania (Log.XXX ()) do różnych wątków i wywołań zwrotnych aplikacji i sprawdzenie, gdzie jest opóźnienie. Jeśli potrzebujesz śledzenia stosu, utwórz nowy wyjątek (po prostu utwórz jeden) i zarejestruj go.
źródło
Co wyzwala ANR?
Zazwyczaj system wyświetla błąd ANR, jeśli aplikacja nie może odpowiedzieć na dane wejściowe użytkownika.
W każdej sytuacji, w której aplikacja wykonuje potencjalnie długotrwałą operację, nie należy wykonywać pracy w wątku interfejsu użytkownika, ale zamiast tego utworzyć wątek roboczy i wykonać tam większość pracy. Dzięki temu wątek interfejsu użytkownika (który steruje pętlą zdarzeń interfejsu użytkownika) działa i zapobiega stwierdzeniu przez system, że kod został zamrożony.
Jak uniknąć błędów ANR
Aplikacje dla systemu Android zwykle działają całkowicie w jednym wątku, domyślnie „wątek interfejsu użytkownika” lub „wątek główny”). Oznacza to, że wszystko, co aplikacja robi w wątku interfejsu użytkownika, a wykonanie tego zabiera dużo czasu, może wywołać okno dialogowe ANR, ponieważ aplikacja nie daje sobie szansy na obsługę zdarzenia wejściowego lub rozgłaszania zamiaru.
W związku z tym każda metoda, która działa w wątku interfejsu użytkownika, powinna wykonywać jak najmniej pracy w tym wątku. W szczególności działania powinny w jak najmniejszym stopniu konfigurować się w kluczowych metodach cyklu życia, takich jak onCreate () i onResume (). Potencjalnie długotrwałe operacje, takie jak operacje sieciowe lub bazodanowe, lub obliczenia kosztowne obliczeniowo, takie jak zmiana rozmiaru map bitowych, powinny być wykonywane w wątku roboczym (lub w przypadku operacji na bazach danych za pośrednictwem żądania asynchronicznego).
Kod: wątek roboczy z klasą AsyncTask
Kod: wykonanie wątku roboczego
Aby wykonać ten wątek roboczy, po prostu utwórz instancję i wywołaj funkcję execute ():
Źródło
http://developer.android.com/training/articles/perf-anr.html
źródło
mój problem z ANR, po wielu pracach dowiedziałem się, że wątek wywołuje zasób, którego nie ma w układzie, zamiast zwrócić wyjątek, otrzymałem ANR ...
źródło
W pliku /data/anr/traces.txt należy szukać wyrażenia „czeka na zablokowanie”
więcej informacji: Inżynier ds. wysokiej wydajności z narzędziami z systemu Android i Play (Google I / O '17)
źródło
Na podstawie odpowiedzi @Horyun Lee napisałem mały skrypt w języku Python, aby pomóc zbadać ANR z
traces.txt
.Błędy ANR będą wyświetlane jako grafika,
graphviz
jeśli zainstalowałeśgrapvhviz
w systemie.Plik png zostanie wyświetlony jak poniżej, jeśli w pliku wykryto błędy ANR
traces.txt
. Jest bardziej intuicyjny.Przykładowy
traces.txt
plik użyty powyżej został pobrany stąd .źródło
Rozważ użycie biblioteki ANR-Watchdog, aby dokładnie śledzić i przechwytywać ślady stosu ANR z dużą szczegółowością. Następnie możesz wysłać je do swojej biblioteki zgłaszania awarii. Polecam używanie
setReportMainThreadOnly()
w tym scenariuszu. Możesz sprawić, by aplikacja zgłosiła niekrytyczny wyjątek punktu zamrożenia lub wymusiła zamknięcie aplikacji, gdy wystąpi błąd ANR.Zwróć uwagę, że standardowe raporty ANR wysyłane do konsoli programisty Google Play często nie są wystarczająco dokładne, aby dokładnie określić problem. Dlatego potrzebna jest biblioteka innej firmy.
źródło