如何从此ANR日志中获得有用的信息 [英] How to get something useful from this ANR log

查看:54
本文介绍了如何从此ANR日志中获得有用的信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我现在已经在ANR上苦苦挣扎了几周,但是对于这这样的日志,我仍然感到盲目一个>.对于stackoverflow来说太长了,我不知道哪一部分可能有用.通常会在初始同步期间在后台处理大量网络请求时发生这种情况(而且我几乎100%确信其中的任何一个都不在主线程中),而且我还在制作很多UI内容,例如填充通过RxJava observables从共享首选项中回收资源视图,因此我正在观察SharedPreferences中的巨大变化,并使用 sample 处理可能的背压的方法.谢谢你的提示,我完全迷路了.

I'm struggling with ANRs for a few weeks now but I still feel blind with logs like this. It is too long for stackoverflow and I have no idea which part might be useful. It happens usually during initial synchronization when there is a ton of network request being processed in the background (and I'm almost 100% sure non of that is in the main thread) and I'm also making a lot of UI stuff like populating recyclerviews from shared preferences via RxJava observables so I'm observing a massive changes in SharedPreferences and using sample method to handle possible back pressure. Thanks for any tips, I'm totally lost.

推荐答案

您在那里有多个进程的线程转储.要找到有用的部分,可以搜索"Cmd line",直到找到您的进程("cz.vcelka.androidapp"的pid为21574).

You have thread dumps for multiple processes in there. To get to the useful part, you can search for "Cmd line" until you find your process ("cz.vcelka.androidapp", the pid was 21574).

如果获得ANR,则意味着您的主线程以某种方式被阻塞,因此您应该查看其堆栈跟踪.这是:

If you get an ANR that means that your main thread is blocked somehow, so you should look at its stack trace. Here it is :

"main" prio=5 tid=1 Waiting
  | group="main" sCount=1 dsCount=0 obj=0x74bc2fa0 self=0xb4db6500
  | sysTid=21574 nice=0 cgrp=default sched=0/0 handle=0xb6fc1b34
  | state=S schedstat=( 0 0 0 ) utm=785 stm=88 core=1 HZ=100
  | stack=0xbe29a000-0xbe29c000 stackSize=8MB
  | held mutexes=
  at java.lang.Object.wait!(Native method)
  - waiting on <0x05853836> (a java.lang.Object)
  at java.lang.Thread.parkFor$(Thread.java:1220)
  - locked <0x05853836> (a java.lang.Object)
  at sun.misc.Unsafe.park(Unsafe.java:299)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:810)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:971)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1278)
  at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:203)
  at android.app.SharedPreferencesImpl$EditorImpl$1.run(SharedPreferencesImpl.java:366)
  at android.app.QueuedWork.waitToFinish(QueuedWork.java:88)
  at android.app.ActivityThread.handleStopActivity(ActivityThread.java:3560)
  at android.app.ActivityThread.-wrap20(ActivityThread.java:-1)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1373)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:148)
  at android.app.ActivityThread.main(ActivityThread.java:5417)
  at java.lang.reflect.Method.invoke!(Native method)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

因此,您的主线程被阻塞,等待 SharedPreferences 代码中的 CountDownLatch .我们可以查看SharedPreferences的源代码以了解更多信息.在某个时候,当您致电 SharedPreferences.Editor.apply() SharedPreferences 代码将对磁盘的写入排队到工作线程中.它还称为 QueuedWork.add(awaitCommit),其中 awaitCommit 是等待写入操作(通过 CountDownLatch 进行)和 QueuedWork的 Runnable .add()是一种方法,当活动的 onPause 方法被调用时,该方法可以使要在主线程上完成工作的时间.就是这样: onPause 被调用,现在主线程被卡在等待工作线程上以完成其写操作.

So your main thread is blocked waiting on a CountDownLatch inside SharedPreferences code. We can look at the source code of SharedPreferences to find out more. At some point when you called SharedPreferences.Editor.apply(), the SharedPreferences code enqueued the write to disk to a worker thread. It also called QueuedWork.add(awaitCommit), where awaitCommit is a Runnable that waits on the write operation (by means of CountDownLatch), and QueuedWork.add() is a method that enqueues work to be done on the main thread when the activity's onPause method is called. That is what happened : onPause was called, and now the main thread is stuck waiting on the worker thread to complete its write operation.

现在问题是您发布的日志不完整.缺少几个线程,包括从未调用 CountDownLatch.countDown()的工作线程,因此无法确定导致死锁的原因.如果您发布整个日志(对于您的流程,我认为其他日志不会有用),我们可能会提供更多帮助.

Now the problem is that the log you posted is incomplete. Several threads are missing, including the worker thread that never called CountDownLatch.countDown(), so it is not possible to tell what is causing the deadlock. If you post the whole log (for your process, I don't think the other ones are going to be useful), we can probably help more.

我注意到这里的其他人遇到了同样的问题.对于他们来说,工作线程被卡在 fsync(2)中.如果文件很大和/或磁盘很忙, fsync 可能真的很慢(几秒钟之内).我想这可能是导致ANR的原因.我不确定这是否会归类为 SharedPreferences 中的错误...似乎有点奇怪,即使从 onPause ...如果这确实是您的问题,我能想到的唯一解决方法是使用 commit()而不是 apply(),因为这样做可以同步写.您应该从后台线程执行此操作,因为在您的特定设置中,似乎需要很长时间才能刷新到磁盘!

Edit : I noticed that someone else here ran into the same problem. For them, the worker thread was stuck in fsync(2). fsync can be really slow (as in multiple seconds) if the file is big and / or the disk is busy. I suppose that could be causing the ANR. I'm not sure if that would classify as a bug in SharedPreferences... Seems a bit weird to trigger possibly long blocking operations on the main thread, even if called from onPause... If this is indeed your problem, the only workaround I can think of would be to use commit() instead of apply(), since that will do the write synchronously. You should do it from a background thread, given that in your particular setup it seems that it can take a pretty long time to flush to disk !

或者您的 SharedPreferences 文件太大,在这种情况下,您可以尝试将其精简(例如使用数据库).

Or maybe your SharedPreferences file is just way too big, in which case you could try slimming it down (by using a database for instance).

这篇关于如何从此ANR日志中获得有用的信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆