RealmError:Realm内存不足

Meh*_*t K 5 android realm realm-java

我使用Realm 3.0.0作为我的Android应用程序的数据库.这就像一个问卷调查应用程序,用户在应用程序中导航很多.当我连续使用应用程序(来回)时,我收到以下错误:

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)
Run Code Online (Sandbox Code Playgroud)

现在我知道这主要原因不是关闭Realm实例.但我已经多次检查过了.而且我很肯定我关闭了每一个打开的实例.

该应用程序有许多活动和片段,所有活动和片段都在他们身上获得Realm实例并将其onCreate关闭onDestroy.还有其他后台网络作业用于上载获取Realm实例的数据.这些作业在完成运行或取消时关闭其Realm实例.

以上所有通过Dagger 2通过注入得到它们的Realm实例:

  @Provides
  @Nullable
  static Realm realm(@Nullable RealmConfiguration configuration) {
    if (configuration != null) {
      Realm.setDefaultConfiguration(configuration);
      return Realm.getDefaultInstance();
    }
    return null;
  }
Run Code Online (Sandbox Code Playgroud)

配置也在同一个Dagger模块中提供.

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

我想我可以在给定时刻在UI线程上拥有最多7-12个片段/活动.0-3其他线程上的0-6个其他引用(后台作业).

此外,我通过Realm.compactRealm(realmConfiguration)每次应用程序启动来压缩我的领域数据库(可能作为一个单独的问题,这似乎并不是一贯的工作).

上面我试图描述性地描述我的Realm用法,而不是详细介绍.现在我的问题是,当用户过度使用应用程序(在活动/片段之间往返(领域注入+数据库读取查询),上传数据(领域注入+数据库读写查询))时,我得到上面发布的内存不足错误.

我也在使用泄漏金丝雀,它没有检测到任何泄漏.(不确定它是否可以)

我是否以不应该使用的方式使用Realm?我应该关闭Realm实例onPause而不是onDestroy吗?我是否应该在一个活动中只有一个领域实例并拥有它的所有碎片(在我的情况下最多为5个)使用此实例?我可以在我的应用程序中进行哪些更改,也许我的应用程序架构可以解决此问题?

我感谢任何帮助,试图解决这个问题.

编辑:我在我的后台线程中分享领域开放逻辑.

我的所有作业共享相同的领域用法,如下所示:Realm通过以下方式延迟注入:

@Inject protected transient Lazy<Realm> lazyRealm;

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

@Override
public void onAdded() {
    realm = lazyRealm.get();
    realm.executeTransaction(realm1 -> {
        //write some stuff into realm
    });
    realm.close();
}
Run Code Online (Sandbox Code Playgroud)

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

@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();
    }
  }
Run Code Online (Sandbox Code Playgroud)

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

Meh*_*t K 8

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

我带走的是,需要非常精细地处理后台线程域访问.感谢您的快速回复和帮助!