【问题标题】:How to use RealmBaseAdapter without memory exceptions?如何在没有内存异常的情况下使用 RealmBaseAdapter?
【发布时间】:2015-04-01 16:36:29
【问题描述】:

我正在尝试找出使用 RealmBaseAdapter 的正确方法。

背景

  • 我有一个包含单个活动和许多片段的应用程序。
  • 主屏幕是一个片段,其中包含一个带有子片段的 ViewPager(在操作栏中带有选项卡)。
  • 每个子片段都包含一个列表视图,该列表视图使用 RealmBaseAdapter 的子类显示领域结果。
  • 当用户在其中一个列表视图中点击某个项目时,会显示一个内部片段(它将主片段替换为其所有子片段)。
  • 为了让 RealmBaseAdapter 工作,必须打开创建 RealmResults 的 Realm 对象(在 getInstance 之后和关闭之前),所以我有一个基础片段,它在 onStart 中创建 Realm 实例并在 onDestroy 中关闭它。

现在的问题
应用程序中有太多与内存相关的崩溃,我想我明白原因了。
问题是总是至少有一个开放的Realm,这避免了它被清理。
意味着境界一直在记忆中生长,永远没有机会被清理。

根据领域的 github 存储库中的一些与内存相关的问题,我了解应该打开和关闭领域以尽可能短的操作,但这与 RealmBaseAdapter 需要打开原始领域对象的事实形成对比终其一生。

任何帮助/想法将不胜感激。

【问题讨论】:

    标签: android out-of-memory realm realm-base-adapter


    【解决方案1】:

    https://realm.io/docs/java/0.80.0/#faq 的常见问题解答中解释了为什么领域的文件大小可能会增加(请参阅“大型领域文件大小”部分)。

    我建议您在应用程序启动或恢复时(以及在它打开 Realm 实例之前)压缩您的 Realm 文件。 Realm.compactRealmFile() 方法是您应该寻找的方法(参见 https://realm.io/docs/java/0.80.0/api/io/realm/Realm.html#compactRealmFile-android.content.Context-)。

    【讨论】:

    • 感谢您的回答。问题不在于磁盘空间不足,而在于内存不足异常。该应用程序成功打开领域,获取数据并将其显示在列表视图中(不止一个)。使用应用程序一段时间后(有时几秒钟,有时更长时间),应用程序在尝试调用 Realm 类的 getInstance 方法时崩溃。
    • 我想强调我这里有一个概念问题。一方面,应关闭领域对象以清除缓存(仅当打开的领域对象为零时才清除内存中的缓存 - 这意味着关闭方法调用量等于 getInstance 方法调用量。但另一方面手 RealmBaseAdapter 要求领域对象(它已创建 RealmResults)在显示结果时始终保持打开状态。在我的情况下,90% 的屏幕显示 RealmResults。这导致应用程序至少有一个打开的领域对象 100%寿命。
    • 我相信这正是导致内存不足异常的原因。
    【解决方案2】:

    来自Realm的Christian。如果没有关于您的代码的更多详细信息,可能很难猜出确切原因,但以下是有关 Realm 工作原理的一些提示,可能会对您有所帮助。

    • 您可以在 UI 线程上打开任意数量的 Realm 实例。 Realm 使用 ThreadLocal 缓存来缓存 Realms。所以在 onCreate 中打开 Realms 并在 onDestroy 中关闭它们是一种完全可行的模式。

    • 所有 RealmBaseAdapter 使用相同的 Realm 缓存版本。

    • 如果您在多个线程中打开相同的 Realm,Realm 将使用额外的内存,因为它必须处理这些 Realm 可能是不同的版本。忘记在后台线程中关闭 Realms 是 OOM 错误的最常见原因。特别是如果您生成自己的线程而不是使用线程池。

    • 使用多个 Realm 文件会增加内存使用量,因为它们是完全独立的数据库。

    • 在紧密循环中迭代大型 RealmResult(例如,在动画重绘期间)可能会导致 OOM 错误。这是因为 Realm 目前使用终结器来清理本机内存,而终结器太慢以至于 GC 线程可能无法跟上。我们在这里对此进行了修复:https://github.com/realm/realm-java/pull/922,但它尚未合并它,因为它也会对整体性能产生负面影响。请注意,渲染 ListAdapter 并不是一个大型数据集,因为它只渲染可见项目,但如果您在较长时间内快速滚动数千个对象,您可能会遇到 OOM。

    希望以上内容对您有所帮助,但如果您仍然看到这些问题,我建议您在 https://github.com/realm/realm-java 创建一个 GitHub 问题,以便我们深入了解。

    【讨论】:

    • 我的问题和这个问题差不多:github.com/realm/realm-java/issues/794.
    • 我们使用工作线程,几乎与示例项目中的工作线程一样。所有写入都在此工作线程上执行,并且没有长事务。我们试图在工作线程创建时 getInstance 并在其终止时调用 close(如您的示例),尝试调用 getInstance 并为此线程上的每个单独操作关闭。
    • 此外,我们在大多数片段上都有领域适配器。我们注意到,如果我们在获取数据后立即关闭为适配器创建 RealmResults 的领域,那么我们会收到一个适当的异常,例如“您正在尝试使用领域对象,但其领域已关闭”。
    • 最后,我们很少有地方使用领域来获取一小部分数据并关闭。所有的 getInstance 调用都与 close 平衡。
    • 在那个 GitHub issue 中,emanuelez 说:“如果你调用 getInstance N 次然后关闭 N 次,那么你调用 close 的唯一 N 次将实际执行本机资源的清理并删除缓存的 Realm实例。”由此我了解到,在“onCreate”中调用“getInstance”并在“onTerminate”中调用“close”是不好的模式。这意味着在应用程序“爆炸”内存之前永远不会清除缓存......
    猜你喜欢
    • 2014-07-18
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 2021-12-26
    • 2014-07-25
    • 2021-12-27
    • 2017-03-05
    • 1970-01-01
    相关资源
    最近更新 更多