首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RealmError:内存大小之外的领域

RealmError:内存大小之外的领域
EN

Stack Overflow用户
提问于 2017-03-31 15:07:58
回答 1查看 3.7K关注 0票数 5

我正在使用王国3.0.0作为我的Android应用程序的DB。这就像一个问卷调查应用程序,用户经常在应用程序中导航。当我连续使用该应用程序(来回)时,我会得到以下错误:

代码语言:javascript
复制
Fatal Exception: io.realm.exceptions.RealmError: Unrecoverable error. mmap() failed: Out of memory size: 1073741824 offset: 0 in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_SharedRealm.cpp line 109
       at io.realm.internal.SharedRealm.nativeGetSharedRealm(SharedRealm.java)
       at io.realm.internal.SharedRealm.(SharedRealm.java:187)
       at io.realm.internal.SharedRealm.getInstance(SharedRealm.java:229)
       at io.realm.internal.SharedRealm.getInstance(SharedRealm.java:204)
       at io.realm.RealmCache.createRealmOrGetFromCache(RealmCache.java:124)
       at io.realm.Realm.getDefaultInstance(Realm.java:210)

现在我知道了造成这种情况的主要原因不是关闭领域实例。但我已经查过好几次了。我肯定我关闭了我打开的每一个实例。

这个应用程序有许多活动和片段,它们都在onCreate上获得了一个领域实例,并在onDestroy上关闭了它。还有其他后台网络作业,它们运行以上载获取领域实例的数据。这些作业在完成运行或取消时关闭它们的领域实例。

以上所有内容都通过Dagger 2通过注入获得了它们的领域实例:

代码语言:javascript
复制
  @Provides
  @Nullable
  static Realm realm(@Nullable RealmConfiguration configuration) {
    if (configuration != null) {
      Realm.setDefaultConfiguration(configuration);
      return Realm.getDefaultInstance();
    }
    return null;
  }

同样的匕首模块也提供了配置。

更具体地说,问卷由ViewPager中显示的许多问题片段组成。每个片段都被注入一个领域。给定问题片段中的许多交互将数据写入DB (一些异步,一些阻塞)。这些片段还查询onResume上的数据库以获取它们的更新数据。其中一些数据也是通过realm.copyFromRealm()复制出领域的。现在,在这种情况发生的任何时候,上传作业很可能运行并从DB读取数据并将其上载到服务器。上传作业完成后,它将写入数据库。

我认为我可以在给定的时刻拥有最多7-12个片段/活动来保存UI线程上的领域引用。以及0-6其他线程上的其他引用(后台作业)。

此外,我在每次发布应用程序时都通过Realm.compactRealm(realmConfiguration)压缩了我的领域DB (也许作为一个单独的问题,这似乎并不能始终如一地完成它的工作)。

上面,我尝试描述我的领域用法,但没有详细说明。现在我的问题是,当用户过度使用应用程序(在活动/片段之间来回走动(领域注入+ DB读取查询),上传数据(领域注入+ DB读和写查询))时,我会从内存错误中得到上面的内容。

我也在使用泄漏金丝雀,它还没有发现任何泄漏。(不确定是否可以)

我是不是以一种不应该被使用的方式来使用领域?我应该关闭领域实例onPause而不是onDestroy吗?我是否应该在一个活动中只有一个领域实例,并让它的所有片段(在我的例子中最多是5个)使用这个实例?为了解决这个问题,我可以对我的应用程序,或者我的应用程序架构进行什么样的修改?

我感谢为解决这个问题而提供的任何帮助。

编辑:我在后台线程中共享领域打开-关闭逻辑。

我的所有作业都共享相同的领域用法,如下所示:领域是通过以下方式惰性地注入的:

@Inject protected transient Lazy<Realm> lazyRealm;

领域对象引用保存在private transient Realm realm;字段中。我正在使用Android优先级作业队列。增加职务时:

代码语言:javascript
复制
@Override
public void onAdded() {
    realm = lazyRealm.get();
    realm.executeTransaction(realm1 -> {
        //write some stuff into realm
    });
    realm.close();
}

并且,当作业被运行时,域被撤回一次,并且该方法的每一个可能的结束都会调用realm.close()

代码语言:javascript
复制
@Override public void onRun() throws Throwable {
    synchronized (syncAdapterLock) {
      realm = lazyRealm.get();
      Answer answer = realm.where(Answer.class).equalTo(AnswerQuery.ID, answerId).findFirst();
      if (answer == null) {
        realm.close();
        throw new RealmException("File not found");
      }
        final File photoFile = new File(answer.getFilePath());
        final Response response = answerService.uploadPhotoAnswer(answerId, RequestBody.create(MediaType.parse("multipart/form-data"), photoFile)).execute();
        if (!response.isSuccessful()) {
          realm.close();
          throw new HttpError(statusCode);
        }
        realm.executeTransaction(realm1 -> {
          answer.setSyncStatus(SyncStatus.SYNCED.getCode());
        });
      }
      realm.close();
    }
  }

正如您所看到的,就我而言,这些后台线程确实正确地关闭了它们的领域实例。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-10 13:26:15

虽然我所有的后台任务确实都调用了realm.close(),但其中一个任务在它的生命周期中称它太晚了。那是我的GPSService,这是一个后台服务。问题是GPS服务在应用程序启动时初始化为Android服务,而Android服务很少被破坏。我正在注入一个领域实例onCreate并关闭它onDestroy。在@EpicPandaForce的评论之后,阅读他关于正确使用领域的文章。我意识到这是泄漏的原因。一个非活套线程在非常长的时间内一直保持一个开放的领域引用,因此,每次发生写事务时,mmap都会膨胀。现在,在每次服务运行时,我都会移动领域get/close,我的问题就解决了。

我的理解是,我们需要非常微妙地对待后台线程领域访问。谢谢你们的快速反应和帮助!

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43144021

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档