Android-как я могу исследовать ANR?



есть ли способ узнать, где мое приложение бросило ANR (приложение не отвечает). Я взглянул на следы.txt-файл в /data, и я вижу трассировку для своего приложения. Это то, что я вижу в трассировке.



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


Как я могу узнать, где проблема? Методы в трассировке - это все методы SDK.



спасибо.

964   10  

10 ответов:

ANR происходит, когда какая-то длительная операция происходит в "главном" потоке. Это поток цикла событий, и если он занят, Android не может обрабатывать дальнейшие события GUI в приложении и, таким образом, вызывает диалог ANR.

теперь, в трассировке вы опубликовали, основной поток, кажется, все в порядке, нет никаких проблем. Это простаивания в очереди, ждет еще одно сообщение сюда. В вашем случае ANR, скорее всего, была более длительной операцией, а не чем-то, что заблокировал поток навсегда, поэтому поток событий восстановился после завершения операции, и ваша трассировка прошла после ANR.

обнаружение, где происходят ANRs, легко, если это постоянный блок (например, тупик, приобретающий некоторые блокировки), но сложнее, если это просто временная задержка. Во-первых, просмотрите свой код и найдите vunerable пятна и длительные операции. Примеры могут включать использование сокетов, блокировок, спящих потоков и других операций блокировки из события нитка. Вы должны убедиться, что все это происходит в отдельных потоках. Если ничего не кажется проблемой, используйте DDMS и включите представление потока. Это показывает все потоки в вашем приложении, похожие на трассировку, которую вы имеете. Воспроизвести ANR, и обновить основной поток в то же время. Это должно показать вам точно, что происходит во время ANR

Вы можете включить StrictMode в API уровня 9 и выше.

StrictMode чаще всего используется для захвата случайного диска или сети доступ к основному потоку приложения, где выполняются операции пользовательского интерфейса полученные и анимации имеют место. Сохраняя основной поток вашего приложения отзывчивый, ты тоже запретить диалоги ANR от показа пользователям.

public void onCreate() {
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                           .detectAll()
                           .penaltyLog()
                           .penaltyDeath()
                           .build());
    super.onCreate();
}

используя penaltyLog() вы можете посмотреть вывод АБР logcat в то время как вы используйте приложение, чтобы увидеть нарушения, как они происходят.

вам интересно, какая задача содержит поток пользовательского интерфейса. Файл трассировки дает вам подсказку, чтобы найти задачу. вам нужно исследовать состояние каждого потока

состояние потока

  • запуск-выполнение кода приложения
  • спящий-называется нить.сон()
  • монитор-ожидание получения блокировки монитора
  • объект ожидания.подождите ()
  • native-выполнение собственного кода
  • vmwait-ожидание на ресурсе виртуальной машины
  • зомби-нить находится в процессе умирания
  • инициализация init - thread (вы не должны видеть это)
  • starting-thread вот-вот начнется (Вы тоже не должны этого видеть)

фокус на приостановлено, состояние монитора. Состояние монитора указывает, какой поток исследуется, и приостановленное состояние потока, вероятно, является основной причиной взаимоблокировки.

основные шаги исследования

  1. найти "в ожидании замок"
    • вы можете найти монитор состояния "связующая нить #15" prio=5 tid=75 MONITOR
    • Вам повезет, если вы найдете "ожидание блокировки"
    • пример: ожидание блокировки (a com.foo.А) удерживается threadid=74
  2. вы можете заметить, что" tid=74 " теперь держите задачу. Так что переходите к tid=74
  3. tid=74 может быть приостановлено состояние! найдите главную причину!

трассировка не всегда содержит "ожидание блокировки". в в этом случае трудно найти главную причину.

Я изучал android в течение последних нескольких месяцев, поэтому я далек от эксперта, но я был очень разочарован документацией по ANRs.

большинство советов, похоже, направлены на то, чтобы избежать их или исправить их, слепо просматривая ваш код, что здорово, но я ничего не мог найти при анализе трассировки.

есть три вещи, которые вам действительно нужно искать с журналами ANR.

1) взаимоблокировки: когда поток находится в ожидании государство, вы можете посмотреть через детали, чтобы найти, кто это "heldby=". Большую часть времени он будет удерживаться сам по себе, но если он удерживается другой нитью, это, вероятно, будет знаком опасности. Иди посмотри на эту нить и посмотри, за что она держится. Вы можете найти петлю, которая является явным признаком, что что-то пошло не так. Это довольно редко, но это первый момент, потому что, когда это происходит, это кошмар

2) ожидание основного потока: Если ваш основной поток находится в состоянии ожидания, проверьте, удерживается ли он по другой нитке. Этого не должно произойти, потому что ваш поток пользовательского интерфейса не должен удерживаться фоновым потоком.

оба этих сценария означают, что вам нужно значительно переработать свой код.

3) тяжелые операции на основной поток: это наиболее распространенная причина ANRs, но иногда один из труднее найти и исправить. Посмотрите на основные детали потока. Прокрутите вниз трассировку стека и пока не увидите классы, которые вы узнаете (из вашего приложения). Посмотрите на методы в трассировке и выяснить, если вы делаете звонков внутри сети, БД и т. д. в таких местах.

наконец, и я прошу прощения за бесстыдно подключив свой собственный код, вы можете использовать анализатор журнала python, который я написал в https://github.com/HarshEvilGeek/Android-Log-Analyzer это будет проходить через ваши файлы журналов, открывать файлы ANR, находить взаимоблокировки, находить ожидающие основные потоки, находить неперехваченные исключения в журналах агентов и печатать все это на экране относительно легко читать. Читать ReadMe файл (который я собираюсь добавить), чтобы узнать, как его использовать. Это помогло мне тонну на прошлой неделе!

всякий раз, когда вы анализируете вопросы синхронизации, отладка часто не помогает, так как замораживание приложения в точке останова сделает проблему уйти.

лучше всего, чтобы вставить много протоколирования вызовов (Log.XXX ()) в различные потоки и обратные вызовы приложения и посмотреть, где задержка находится. Если вам нужен stacktrace, создайте новое исключение (просто создайте экземпляр) и запишите его.

что вызывает ANR?

как правило, система отображает ANR, если приложение не может ответить на ввод пользователя.

в любой ситуации, когда ваше приложение выполняет потенциально длительную операцию, вы не должны выполнять работу в потоке пользовательского интерфейса, а вместо этого создать рабочий поток и выполнять большую часть работы там. Это сохраняет поток пользовательского интерфейса (который управляет циклом событий пользовательского интерфейса) и предотвращает вывод системы о том, что ваш код заморожен.

Как избежать ANRs

приложений Android обычно полностью работают на один поток по умолчанию "поток пользовательского интерфейса" или "основной поток"). Это означает, что все, что ваше приложение делает в потоке пользовательского интерфейса, которое занимает много времени, может вызвать диалоговое окно ANR, потому что ваше приложение не дает себе возможности обрабатывать входные события или передачи намерений.

поэтому любой метод, который выполняется в потоке пользовательского интерфейса, должен выполнять как можно меньше работы этот поток. В частности, мероприятия должны делать как можно меньше для настройки в ключевых методах жизненного цикла, таких как onCreate() и onResume(). Потенциально длительные операции, такие как операции с сетью или базой данных, или вычислительно дорогостоящие вычисления, такие как изменение размера растровых изображений, должны выполняться в рабочем потоке (или в случае операций с базами данных с помощью асинхронного запроса).

код: рабочий поток с классом AsyncTask

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

Код: Выполнить Рабочий поток

чтобы выполнить этот рабочий поток, просто создайте экземпляр и вызовите execute ():

new DownloadFilesTask().execute(url1, url2, url3);

источник

http://developer.android.com/training/articles/perf-anr.html

моя проблема с ANR, после большой работы я узнал, что поток вызывал ресурс , который не существовал в макете, вместо того, чтобы возвращать исключение, я получил ANR ...

нужно искать "ожидание блокировки" в / data/anr / traces.txt file

enter image description here

дополнительные сведения: инженер для высокой производительности с помощью инструментов из Android и Play (Google I/O '17)

Basic на @Horyun Lee ответ, я написал маленький питон скрипт чтобы помочь исследовать ANR от traces.txt.

ANRs будет выводиться в виде графики по graphviz Если вы установили grapvhviz на вашей системе.

$ ./anr.py --format png ./traces.txt

png будет выводиться, как показано ниже, если в файле обнаружены ANRs traces.txt. Это более интуитивно понятно.

enter image description here

пример traces.txt файл, используемый выше, был получен из здесь.

рассмотрите возможность использования ANR-Watchdog библиотека для точного отслеживания и захвата трассировок стека ANR с высоким уровнем детализации. Затем их можно отправить в библиотеку отчетов о сбоях. Я рекомендую использовать setReportMainThreadOnly() в этом случае. Вы можете либо заставить приложение бросить несмертельное исключение точки замораживания, либо заставить приложение принудительно выйти, когда произойдет ANR.

обратите внимание, что стандартные отчеты ANR, отправленные на консоль разработчика Google Play, часто недостаточно точны, чтобы определите точную проблему. Вот почему необходима сторонняя библиотека.

Comments

    Ничего не найдено.