微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

尝试写入时,什么可能导致 Realm 锁定?

如何解决尝试写入时,什么可能导致 Realm 锁定?

我的团队目前在跨所有平台(Android、iOS 和 UWP)的 Xamarin.Forms 应用中遇到问题。 Realm 经常会变得无响应,再次使用它的唯一方法关闭应用程序。在过去几个月中,它变得更加频繁且易于重现,但我们一直无法确定原因或解决方法

我们已经确定了一些可能有助于确定正在发生的事情的模式。我们注意到,每当需要从数据库获取信息时,我们都会看到工作线程卡在 Realm.Write() 调用上。这种行为看起来好像在 Realm 系统中发生了死锁。关于它停留在哪个 Write() 调用上并不一致,似乎基于 Realm 失败的时间是随机的。此时,通过任何方法(例如 Find()All()Remove() 等)访问此领域的任何其他尝试也会卡住。我们还确认 Write() 中的代码此时永远不会运行,因为我们可以将独立于领域的日志记录调用放在第一行并且永远不会在我们的日志中看到它。

一旦发生此问题,除此之外还会发生其他一些问题。我们的应用程序中还有另外两个 Realms,它们处理完全独立的数据,因此没有重叠的代码。这些 Realm 从来都不是这个问题的原因,但是当问题 Realm 卡住时,有时会导致其他 Realm 也卡在他们的下一次调用中。此问题有时也会在应用的两次使用之间持续存在,导致对 Realm 的第一次调用卡住,需要完全重新安装才能修复。

由于我们的应用程序使用基于 Reactive 的编程,我们不得不以稍微不同的方式构建我们处理数据库的方式。对于 Realm 问题,我们有一个服务可以在可观察流中保持单个实例处于活动状态,然后可以订阅该实例以观察变化。我在这文章的末尾添加了一些这种架构的例子。我们还通过此流路由所有其他不可观察的操作,但是在调试期间,我们已经能够将这些调用移动到它们自己的独立领域实例,几乎没有问题/功能没有变化。

目前,我们认为这很可能与我们如何将 Realm 转换为可观察系统有关,或者与我们的 Realm 以某种方式崩溃/损坏有关。

RealmStream 声明:

_realmStream = Observable
    .Start(() => Realm.GetInstance(_dbConfig),_scheduler)
    .Do(_ => logger.LogTrace("Realm created"),() => logger.LogTrace("Realm stream completed"))
    .Replay()
    .AutoConnect();

RealmStream 使用示例:

public IObservable<IChangeSet<TResult>> GetChangeSetStream<TSource,TResult>(Func<Realm,IQueryable<TSource>> selector,Func<TSource,TResult> transformFactory) where TSource : RealmObject
{           
    return _realmStream
        .Select(realm =>
            selector(realm)
                .AsRealmCollection()
                .ToObservableChangeSet<IRealmCollection<TSource>,TSource>()
                .SubscribeOn(_scheduler)
                .Transform(transformFactory)
                .disposeMany())
        .Switch()
        .Catch<IChangeSet<TResult>,Exception>(ex =>
        {
            _logger.LogError(ex,"Error getting property change stream");
            return Observable.Return<IChangeSet<TResult>>(default);
        })
        .SubscribeOn(_scheduler);
}

不可观察的领域方法

public async Task Run(Action<Realm> action)
{
    await _realmStream
        .Do(action)
        .SubscribeOn(_scheduler);
}

public async Task<TResult> Run<TResult>(Func<Realm,TResult> action)
{
    return await _realmStream
        .Select(action)
        .SubscribeOn(_scheduler);
}

到目前为止,我们已经尝试了以下方法

  • 确保 Realm 和 Xamarin 都是最新版本
  • 减少 Realm.Write()数量(小幅改进)
  • 将每个 Realm 函数移到我们的可观察系统中(没有明显变化,我们的大多数函数已经这样做了)
  • 尝试将不需要 observable 的所有内容移至使用独立领域实例(增加锁定频率)
  • 尝试将所有内容从我们的单个 Realm 实例中移开。我们无法做到这一点,因为我们无法确定如何在不引起重大性能问题的情况下正确处理某些可观察事件(例如 RealmObject 被删除

解决方法

realm.Write 需要获取写锁,根据您的描述,您似乎确实遇到了死锁,其中具有打开写事务的线程等待另一个卡在 realm.Write 上的线程称呼。如果您能够在附加调试器的情况下重现手牌,您可以检查线程窗口并尝试查明有问题的代码。

This article 提供了一些有关调试死锁的技巧。不幸的是,如果没有整个项目和重现案例,就很难查明原因。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。