如何从这个ANR日志中获得有用的东西

Sem*_*cer 6 android sharedpreferences android-anr-dialog

我现在用ANR的几周艰难,但我还是觉得盲像日志这样.stackoverflow太长了,我不知道哪个部分可能有用.它通常在初始同步期间发生,当时在后台处理了大量的网络请求(我几乎100%确定它不在主线程中)并且我也在制作很多UI内容,比如填充通过RxJava observables从共享偏好中回收视图,因此我观察到SharedPreferences的大量变化,并使用样本方法来处理可能的背压.感谢任何提示,我完全迷失了.

Sam*_*ter 13

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

如果你得到一个ANR意味着你的主线程被某种方式阻塞了,所以你应该看一下它的堆栈跟踪.这里是 :

"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)
Run Code Online (Sandbox Code Playgroud)

所以你的主线程被阻塞等待CountDownLatch内部SharedPreferences代码.我们可以查看SharedPreferences的源代码以了解更多信息.在您调用SharedPreferences.Editor.apply()的某个时刻,SharedPreferences代码将写入磁盘的行写入工作线程.它还称为QueuedWork.add(awaitCommit),其中awaitCommitRunnable等待写操作(通过CountDownLatch),并且QueuedWork.add()是一种方法,当调用activity的方法时,它将在主线程上完成工作onPause.这就是发生的事情:onPause被调用,现在主线程等待工作线程完成其写操作.

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

编辑:我注意到其他人遇到了同样的问题.对他们来说,工人的线程陷入困境fsync(2).fsync如果文件很大和/或磁盘很忙,可能会很慢(如在多秒内).我想这可能会导致ANR.我不确定是否会将其归类为错误SharedPreferences...在主线程上触发可能的长阻塞操作似乎有点奇怪,即使从onPause... 调用如果这确实是你的问题,我唯一能解决的问题想到会用commit()而不是apply(),因为那样会同步写.您应该从后台线程执行此操作,因为在您的特定设置中,似乎需要很长时间才能刷新到磁盘!

或者也许你的SharedPreferences文件太大了,在这种情况下你可以尝试减少它(例如使用数据库).

  • 所以看起来从`apply()`到`commit()`的转变确实显着改善了这种情况,因为我已经在后台线程中调用了它.当我非常努力地尝试时,我仍然可以得到ARN,但我想现在接下来的逻辑推动是为了简化"SharedPreferences"的工作. (2认同)