Android - bir ANR'yi nasıl araştırabilirim?


153

Benim app bir ANR (Uygulama Yanıt Vermiyor) attı bulmak için bir yolu var mı. / Data içindeki traces.txt dosyasına bir göz attım ve uygulamam için bir iz görüyorum. İzde gördüğüm bu.

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

Sorunun nerede olduğunu nasıl öğrenebilirim? İzlemedeki yöntemlerin tümü SDK yöntemleridir.

Teşekkürler.


2
Bu tür bir raporum var, aynı zamanda da oluyor android.os.MessageQueue.nativePollOnce(Native Method). Güvenle göz ardı edebilir miyim?
rds

Yanıtlar:


124

"Ana" iş parçacığında uzun bir işlem gerçekleştiğinde bir ANR gerçekleşir. Bu olay döngüsü iş parçacığıdır ve meşgulse, Android uygulamadaki başka GUI olaylarını işleyemez ve böylece bir ANR iletişim kutusu atar.

Şimdi, izlediğiniz izde, ana iş parçacığı iyi görünüyor, sorun yok. MessageQueue'da boşta çalışıyor, başka bir iletinin gelmesini bekliyor. Sizin durumunuzda ANR, iş parçacığını kalıcı olarak engelleyen bir şey yerine daha uzun bir işlemdi, bu nedenle işlem tamamlandıktan sonra olay iş parçacığı kurtarıldı ve izlemeniz geçti ANR'den sonra.

ANR'lerin nerede olduğunu tespit etmek, kalıcı bir bloksa (örneğin, bazı kilitleri alan kilitlenme) kolaydır, ancak sadece geçici bir gecikme olduğunda daha zordur. İlk olarak, kodunuzu gözden geçirin ve müthiş noktalar ve uzun süren operasyonlar arayın. Örnekler, olay dizisinin içinden soket, kilit, iplik uykusu ve diğer engelleme işlemlerini kullanmayı içerebilir. Bunların ayrı iş parçacıklarında olduğundan emin olmalısınız. Sorun görünen hiçbir şey yoksa, DDMS kullanın ve iş parçacığı görünümünü etkinleştirin. Bu, uygulamanızdaki izlere benzer tüm konuları gösterir. ANR'yi yeniden oluşturun ve ana iş parçacığını aynı anda yenileyin. Bu size ANR zamanında neler olup bittiğini göstermelidir


6
tek sorun "ANR yeniden" :-). Bu yığın izleme şovunun ana iş parçacığının nasıl 'boşta' olduğunu açıklar mısınız, bu harika olurdu.
Blundell

20
Yığın izleme, ana iş parçacığının Looper (ileti döngüsü uygulaması) içinde olduğunu ve Object.wait aracılığıyla zamanlanmış bir bekleme yaptığını gösterir. Bu, mesaj döngülerinin şu anda gönderilecek mesajı olmadığı ve yeni mesajların gelmesini beklediği anlamına gelir. Sistem, bir mesaj döngüsünün bir mesajı işlemek için çok fazla zaman harcadığını ve Sıra. Döngüler iletileri bekliyorsa, açıkçası bu gerçekleşmez.
Yakında

3
@Soonil Merhaba Binder iş parçacığı 3, Binder iş parçacığı 2 JDWP iblis prio 5. gibi bölümlerin geri kalanı ne anlama geldiğini biliyor musunuz sCount, dsCount, obj, sysTid, güzel zamanlama anlamına gelir. ayrıca VMWAIT, RUNNABLE, NATIVE gibi bilgiler var
minhaz

1
Uygulamam NDK tabanlı, aynı ANR'yi görüyorum. Ayrıca, ana iplik iyi. Ben DDMS denedim ve donma zaman işçi iş parçacığı yenileme. Ne yazık ki tüm aldığım tek bir satır NativeStart :: run. DDMS iş parçacığı görünümü yerel NDK iş parçacıklarını denetleyebiliyor mu? Ayrıca: StrictMode hiçbir şey bulamadı.
Bram

6
Çıktının iyi bir açıklaması için bkz. Elliotth.blogspot.com/2012/08/… .
yakında

96

StrictMode'u API seviye 9 ve üstünde etkinleştirebilirsiniz .

StrictMode, genellikle UI işlemlerinin alındığı ve animasyonların gerçekleştiği uygulamanın ana iş parçacığında yanlışlıkla disk veya ağ erişimini yakalamak için kullanılır. Uygulamanızın ana iş parçacığını duyarlı tutarak ANR iletişim kutularının kullanıcılara gösterilmesini de engelleyebilirsiniz .

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

kullanarak penaltyLog()uygulamanızı kullanırken ihlallerin gerçekleştiğini görmek için adb logcat'in çıktısını izleyebilirsiniz.


StrictMode bir türe çözümlenemez. Önce içe aktarmam gereken bir şey var mı? CTRL + ÜST KRKT + O tuşlarına basmak yardımcı olmaz.
kuchi

23
küçük ipucu - eğer üretime dahil edilmesini önlemek için (BuildConfig.DEBUG) kullanın ...
Amir Uval

@uval "üretime dahil olmayı önlemek" ile ne demek istiyorsun? !!
Muhammed Refaat

2
@MuhammedRefaat herhangi bir ANR'yi engellemez. 5 saniye sonra uygulamayı hemen kilitler. Örneğin, ana iş parçacığındaki veritabanına erişirseniz ve 2 saniye sürerse, bir ANR elde edemezsiniz, ancak StrictMode uygulamayı kilitler. StrictMode kesinlikle üretim değil, hata ayıklama aşaması içindir.
Amir Uval

1
@MuhammedRefaat, sorunuza yanıtımı ekledi.
Amir Uval

80

Hangi görevin bir UI İş Parçacığına sahip olduğunu merak ediyorsunuz. İzleme dosyası, görevi bulmanız için bir ipucu verir. her bir iş parçacığının durumunu araştırmanız gerekir

İş parçacığının durumu

  • çalışan - uygulama kodunu yürütme
  • sleeping - Thread.sleep () olarak adlandırılır
  • monitör - monitör kilidi almayı bekliyor
  • bekleyin - Object.wait () içinde
  • yerli - yerel kodu yürütme
  • vmwait - VM kaynağı bekliyor
  • zombi - iplik ölüyor sürecinde
  • init - iş parçacığı başlatılıyor (bunu görmemelisiniz)
  • başlangıç ​​- konu başlamak üzere (bunu da görmemelisiniz)

SUSPENDED, MONITOR durumuna odaklanın. İzleme durumu, hangi iş parçacığının araştırıldığını ve iş parçacığının SUSPENDED durumunun muhtemelen kilitlenmenin ana nedeni olduğunu gösterir.

Temel araştırma adımları

  1. "Kilitlenmeyi bekliyor" bul
    • monitör durumunu bulabilirsiniz "Binder Thread # 15" prio = 5 tid = 75 MONITOR
    • "kilitlemek için bekliyor" bulursanız şanslısınız
    • örnek: threadid = 74 tarafından tutulan <0xblahblah> (com.foo.A) 'yı kilitlemek için bekliyor
  2. Şimdi "tid = 74" un bir görevi tuttuğunu görebilirsiniz. Yani tid = 74'e git
  3. tid = 74 belki ASMA durum! ana nedeni bulmak!

izleme her zaman "kilitlenmeyi bekliyor" içermez. bu durumda ana nedeni bulmak zordur.


1
Güzel açıklama. ANR günlüklerini anlamak artık daha kolay. Ama yine de nedenini anlamak için bir sorunum var çünkü adım 1'de iş parçacığı kimliğini kolayca bulabiliyorum, ancak 2. adımda, nerede olduğunu, durumu kontrol etmek için gitmeye çalıştığımda, bulamıyorum . Bununla nasıl devam edileceği hakkında bir fikrin var mı?
THZ

1
Ben - waiting to lock an unknown objectiçeride "HeapTaskDaemon" daemon prio=5 tid=8 Blocked . Birisi yardımcı olabilir ne anlama geliyor?
Hilal

13

Son birkaç aydır android öğreniyorum, bu yüzden bir uzmandan çok uzakım, ancak ANR'lerle ilgili belgelerden gerçekten hayal kırıklığına uğradım.

Tavsiyelerin çoğu onlardan kaçınmaya veya körü körüne kodunuza bakarak düzeltmeye yönelik gibi görünüyor, bu harika, ancak izi analiz etmede hiçbir şey bulamadım.

ANR günlüklerinde gerçekten aramanız gereken üç şey vardır.

1) Deadlocks: Bir iş parçacığı WAIT durumundayken, kimin "heldby =" olduğunu bulmak için ayrıntıları inceleyebilirsiniz. Çoğu zaman, kendi başına tutulur, ancak başka bir iş parçacığı tarafından tutulursa, bu bir tehlike işareti olacaktır. Git o konuya bak ve ne tarafından tutulduğunu gör. Bir döngü bulabilirsiniz, bu da bir şeyin yanlış gittiğinin açık bir işaretidir. Bu oldukça nadirdir, ancak ilk nokta çünkü gerçekleştiğinde bir kabus

2) Ana iplik Bekliyor: Ana ipliğiniz BEKLEME durumundaysa, başka bir iplik tarafından tutulup tutulmadığını kontrol edin. Bu olmamalı, çünkü UI iş parçacığınız arka plan iş parçacığı tarafından tutulmamalıdır.

Bu senaryoların her ikisi de, kodunuzu önemli ölçüde yeniden işlemeniz gerektiği anlamına gelir.

3) Ana iplikte ağır işlemler: Bu, ANR'lerin en yaygın nedenidir, ancak bazen bulmak ve düzeltmek daha zordur. Ana iş parçacığı ayrıntılarına bakın. Yığın izini ve tanıdığınız sınıfları (uygulamanızdan) görene kadar aşağı kaydırın. İzlemedeki yöntemlere bakın ve bu yerlerde ağ aramaları, db aramaları vb. Yapıp yapmadığınızı belirleyin.

Son olarak, ben utanmadan kendi kodunu takmayı dolayı özür, ne de yazdığı piton log analiz kullanabilirsiniz https://github.com/HarshEvilGeek/Android-Log-Analyzer Bu günlük dosyaları geçeceği açık ANR dosyaları bulmak ana kilitleri bulmak, bekleyen ana konuları bulmak, ajan günlüklerinizde yakalanmamış istisnalar bulmak ve nispeten kolay okunur bir şekilde hepsini ekranda yazdırın. Nasıl kullanılacağını öğrenmek için ReadMe dosyasını (eklemek üzere olduğum) okuyun. Geçen hafta bana bir ton yardım etti!


4

Zamanlama sorunlarını her analiz ettiğinizde, uygulamanın bir kesme noktasında dondurulması sorunu ortadan kaldıracağından hata ayıklama çoğu zaman yardımcı olmaz.

En iyi seçeneğiniz, uygulamanın farklı iş parçacıklarına ve geri aramalarına çok sayıda günlük arama (Log.XXX ()) eklemek ve gecikmenin nerede olduğunu görmektir. Bir yığın izlemeye ihtiyacınız varsa, yeni bir İstisna oluşturun (sadece bir tane oluşturun) ve günlüğe kaydedin.


2
Yığın izlemeye ihtiyacınız varsa yeni bir istisna oluşturma önerisi için teşekkür ederiz. Hata ayıklama yaparken bu çok yararlı :)
kuchi

3

ANR'yi ne tetikler?

Genellikle, bir uygulama kullanıcı girişine yanıt veremezse sistem bir ANR görüntüler.

Uygulamanızın potansiyel olarak uzun bir işlem gerçekleştirdiği her durumda, UI iş parçacığı üzerinde çalışma yapmamalı, bunun yerine bir işçi iş parçacığı oluşturmalı ve işin çoğunu orada yapmalısınız. Bu, kullanıcı arabirimi olay döngüsünü çalıştıran UI iş parçacığını çalışır durumda tutar ve sistemin kodunuzun donmuş olduğu sonucuna varmasını önler.

ANR'lerden kaçınma

Android uygulamaları normalde varsayılan olarak "UI iş parçacığı" veya "ana iş parçacığı" olarak tek bir iş parçacığında çalışır). Bu, uygulamanızın UI iş parçacığında tamamlanması uzun süren herhangi bir şeyin ANR iletişim kutusunu tetikleyebileceği anlamına gelir, çünkü uygulamanız giriş girdisini veya niyet yayınlarını işleme şansı vermez.

Bu nedenle, UI iş parçacığında çalışan herhangi bir yöntem bu iş parçacığında mümkün olduğunca az iş yapmalıdır. Özellikle, etkinlikler onCreate () ve onResume () gibi temel yaşam döngüsü yöntemlerinde kurulabilmek için mümkün olduğunca az şey yapmalıdır. Ağ veya veritabanı işlemleri gibi potansiyel olarak uzun süre çalışan işlemler veya bitmap'leri yeniden boyutlandırma gibi hesaplamalı olarak pahalı hesaplamalar bir çalışan iş parçacığında (veya veritabanları işlemleri durumunda, eşzamansız bir istek yoluyla) gerçekleştirilmelidir.

Kod: AsyncTask sınıfıyla çalışan iş parçacığı

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

Kod: Çalışan iş parçacığını yürüt

Bu çalışan iş parçacığını yürütmek için bir örnek oluşturun ve execute () öğesini çağırın:

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

Kaynak

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


1

ANR ile benim sorunum, çok işten sonra bir iş parçacığı, bir istisna döndürmek yerine, düzende mevcut olmayan bir kaynak çağırdığını öğrendim, ANR var ...


bu çok garip
Nilabja


0

@Horyun Lee cevabı hakkında temel olarak, ANR'yi araştırmaya yardımcı olmak için küçük bir python betiği yazdım .traces.txt .

ANR'ler sisteminize graphvizyüklediyseniz grafik olarak çıktı verir grapvhviz.

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

Dosyada algılanan ANR'ler varsa, bir png aşağıdaki gibi çıkacaktır traces.txt. Daha sezgisel.

resim açıklamasını buraya girin

traces.txtYukarıda kullanılan örnek dosya buradan alınmıştır .


0

ANR yığın izlerini yüksek düzeyde ayrıntılı olarak izlemek ve yakalamak için ANR-Watchdog kütüphanesini kullanmayı düşünün . Daha sonra bunları kilitlenme raporlama kitaplığınıza gönderebilirsiniz. Kullanmanızı öneririmsetReportMainThreadOnly()Bu senaryoda . Uygulamanın donma noktasının ölümcül olmayan bir istisnasını atmasını sağlayabilir veya ANR gerçekleştiğinde uygulama gücünün kapanmasını sağlayabilirsiniz.

Google Play Geliştirici konsolunuza gönderilen standart ANR raporlarının genellikle sorunu tam olarak belirleyecek kadar doğru olmadığını unutmayın. Bu nedenle üçüncü taraf bir kütüphaneye ihtiyaç vardır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.