导致大量 ANR 的领域
Realm causing lots of ANR
在我自己的测试中,我没有遇到这个问题,但是一旦我的应用程序发布,ANR 就开始大量涌入。我的应用程序目前有 22 个 ANRs,其中一些被报告多达 100 次。所有的痕迹似乎都来自试图在 UI 线程上创建一个新的 Realm 实例。
"main" prio=5 tid=1 MONITOR
| group="main" sCount=1 dsCount=0 obj=0x4183ede0 self=0x417548b8
| sysTid=19680 nice=0 sched=0/0 cgrp=apps handle=1073975684
| state=S schedstat=( 2816413167 710323137 3658 ) utm=215 stm=66 core=1
at io.realm.Realm.createAndValidate(Realm.java:~495)
- waiting to lock <0x41df9c98> held by tid=12 (IntentService[UASyncService])
at io.realm.Realm.create(Realm.java:486)
at io.realm.Realm.getInstance(Realm.java:404)
at io.realm.Realm.getInstance(Realm.java:366)
at io.realm.Realm.getInstance(Realm.java:347)
我相信这个问题的根源是,正如 beeender 提到的,我在工作线程中有一个打开的 Realm 事务,它阻止了我在 UI 线程上获取 Realm 实例的尝试,导致 ANR。
有解决办法以后再更新
*编辑:添加更新信息。
Realm's introduction example 展示了他们使用 AsyncTask 进行读写。
任何昂贵的 I/O,无论是来自网络、数据库还是大文件,通常都应该远离主线程,因为它会导致缓慢 UI。在没有看到您的代码的情况下,我猜想如果您收到 ANR,您可能正在做一些对于主线程而言过于复杂的事情。
Realm 不再有这个问题。
供参考我当时的解决方案是:
感谢 beeender 为我指明了正确的方向并链接了此 PR https://github.com/realm/realm-java/pull/1297
问题
当存在待处理的 Realm 事务时,在不同线程上对 Realm.getInstance
的任何调用都将阻塞,直到待处理的事务被提交或取消。
在我的例子中,我有一个 IntentService,它用现有的用户数据填充我的 Realm,同时我尝试通过在 UI 线程上查询 Realm 来显示任何当前数据。虽然查询很简单,通常不会引起任何问题,但如果 IntentService 中有待处理的事务,调用 Realm.getInstance
将被阻塞,阻塞 UI 线程,可能导致 ANR。
我的第一个解决方案尝试是拉出 beeender 的 PR 分支并创建一个 jar。我相信这个修复确实让我更进一步,允许在不阻塞的情况下创建 Realm 实例,但是 UI 线程仍然被我试图在 UI 线程上执行的小事务阻塞。
解决方案
我实施的解决方案涉及几个步骤:
- 为我的所有模型创建重复对象。副本不扩展 RealmObject(因为 RealmObjects 不能跨线程使用。)
- 将对 Realm 的所有访问移至后台线程。基本上我将查询包装在 AsyncTasks 中并添加了 return 模型的非 RealmObject 版本的监听器。
- 多做小额交易而不是少做大额交易。之前我在创建许多新 RealmObject 的循环的任一侧开始并提交事务,现在我开始并提交每个对象的事务。这样做的目的是减少 Realm 可能处于打开事务状态的总不间断时间,这样我为 UI 提供数据的查询就可以完成而不必等待那么长时间。
结论
最初我对使用 Realm 犹豫不决,因为它仍处于测试阶段,而且需要注意的是 RealmObjects 不能跨线程使用。经过一些测试后,我确信我可以毫无问题地在 UI 线程上执行简单的查询(尽管我的直觉仍然有罪恶感。)
Overall Realm 是一个值得关注的好项目,但我觉得它还没有为大型商业项目做好准备。在这个项目上使用 Realm 可能节省了一些前期时间,但它让许多不满意的客户和难以诊断的问题付出了代价。
*编辑:澄清问题。
在我自己的测试中,我没有遇到这个问题,但是一旦我的应用程序发布,ANR 就开始大量涌入。我的应用程序目前有 22 个 ANRs,其中一些被报告多达 100 次。所有的痕迹似乎都来自试图在 UI 线程上创建一个新的 Realm 实例。
"main" prio=5 tid=1 MONITOR
| group="main" sCount=1 dsCount=0 obj=0x4183ede0 self=0x417548b8
| sysTid=19680 nice=0 sched=0/0 cgrp=apps handle=1073975684
| state=S schedstat=( 2816413167 710323137 3658 ) utm=215 stm=66 core=1
at io.realm.Realm.createAndValidate(Realm.java:~495)
- waiting to lock <0x41df9c98> held by tid=12 (IntentService[UASyncService])
at io.realm.Realm.create(Realm.java:486)
at io.realm.Realm.getInstance(Realm.java:404)
at io.realm.Realm.getInstance(Realm.java:366)
at io.realm.Realm.getInstance(Realm.java:347)
我相信这个问题的根源是,正如 beeender 提到的,我在工作线程中有一个打开的 Realm 事务,它阻止了我在 UI 线程上获取 Realm 实例的尝试,导致 ANR。
有解决办法以后再更新
*编辑:添加更新信息。
Realm's introduction example 展示了他们使用 AsyncTask 进行读写。
任何昂贵的 I/O,无论是来自网络、数据库还是大文件,通常都应该远离主线程,因为它会导致缓慢 UI。在没有看到您的代码的情况下,我猜想如果您收到 ANR,您可能正在做一些对于主线程而言过于复杂的事情。
Realm 不再有这个问题。
供参考我当时的解决方案是:
感谢 beeender 为我指明了正确的方向并链接了此 PR https://github.com/realm/realm-java/pull/1297
问题
当存在待处理的 Realm 事务时,在不同线程上对 Realm.getInstance
的任何调用都将阻塞,直到待处理的事务被提交或取消。
在我的例子中,我有一个 IntentService,它用现有的用户数据填充我的 Realm,同时我尝试通过在 UI 线程上查询 Realm 来显示任何当前数据。虽然查询很简单,通常不会引起任何问题,但如果 IntentService 中有待处理的事务,调用 Realm.getInstance
将被阻塞,阻塞 UI 线程,可能导致 ANR。
我的第一个解决方案尝试是拉出 beeender 的 PR 分支并创建一个 jar。我相信这个修复确实让我更进一步,允许在不阻塞的情况下创建 Realm 实例,但是 UI 线程仍然被我试图在 UI 线程上执行的小事务阻塞。
解决方案
我实施的解决方案涉及几个步骤:
- 为我的所有模型创建重复对象。副本不扩展 RealmObject(因为 RealmObjects 不能跨线程使用。)
- 将对 Realm 的所有访问移至后台线程。基本上我将查询包装在 AsyncTasks 中并添加了 return 模型的非 RealmObject 版本的监听器。
- 多做小额交易而不是少做大额交易。之前我在创建许多新 RealmObject 的循环的任一侧开始并提交事务,现在我开始并提交每个对象的事务。这样做的目的是减少 Realm 可能处于打开事务状态的总不间断时间,这样我为 UI 提供数据的查询就可以完成而不必等待那么长时间。
结论
最初我对使用 Realm 犹豫不决,因为它仍处于测试阶段,而且需要注意的是 RealmObjects 不能跨线程使用。经过一些测试后,我确信我可以毫无问题地在 UI 线程上执行简单的查询(尽管我的直觉仍然有罪恶感。)
Overall Realm 是一个值得关注的好项目,但我觉得它还没有为大型商业项目做好准备。在这个项目上使用 Realm 可能节省了一些前期时间,但它让许多不满意的客户和难以诊断的问题付出了代价。
*编辑:澄清问题。