android - 如何从此 ANR 日志中获取有用的信息

标签 android sharedpreferences android-anr-dialog

几周以来,我一直在与 ANR 作斗争,但我仍然对 this 这样的日志感到茫然。 . stackoverflow 太长了,我不知道哪一部分可能有用。 它通常发生在初始同步期间,当时后台正在处理大量网络请求(我几乎 100% 确定主线程中没有这些请求),而且我还制作了很多 UI 东西,比如填充通过 RxJava observables 从共享偏好中回收 View ,所以我观察到 SharedPreferences 的巨大变化并使用 sample处理可能的背压的方法。感谢您提供任何提示,我完全迷路了。

最佳答案

那里有多个进程的线程转储。要找到有用的部分,您可以搜索“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)

因此,您的主线程被阻止等待 SharedPreferences 代码中的 CountDownLatch。我们可以查看 SharedPreferences 的源代码以了解更多信息。在某个时候你调用 SharedPreferences.Editor.apply() , SharedPreferences 代码将磁盘写入排队到工作线程。它也称为 QueuedWork.add(awaitCommit) ,其中 awaitCommit 是等待写入操作的 Runnable(通过 CountDownLatch),QueuedWork.add() 是一种方法,当调用 Activity 的 onPause 方法时,将要在主线程 上完成的工作排入队列。事情就是这样:onPause 被调用,现在主线程卡在等待工作线程完成其写入操作。

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

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

或者您的 SharedPreferences 文件太大了,在这种情况下您可以尝试缩小它(例如使用数据库)。

关于android - 如何从此 ANR 日志中获取有用的信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37549578/

相关文章:

android - 应用程序替换另一个?

java - 保存和检索数组并在 ListView 中显示

Android:调用 getExternalFilesDir(null) 时出现 ANR

Android 在调试时没有响应。如果不在调试应用程序中正常工作

android - 从哪里开始 : Creating a PDF in my Android application

Android Studio 调色板被禁用

Android 5.0/ Lollipop : Force rescan of/system/priv-app

android - 当用户通过 Market Place 更新时,我的 Android 应用程序和数据库会发生什么情况?

java - 使用共享首选项来保存一些整数

android - 如何从 Activity 和 BroadcastReceiver 重现应用程序无响应 (ANR)