我正在使用王国3.0.0作为我的Android应用程序的DB。这就像一个问卷调查应用程序,用户经常在应用程序中导航。当我连续使用该应用程序(来回)时,我会得到以下错误:
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通过注入获得了它们的领域实例:
@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优先级作业队列。增加职务时:
@Override
public void onAdded() {
realm = lazyRealm.get();
realm.executeTransaction(realm1 -> {
//write some stuff into realm
});
realm.close();
}并且,当作业被运行时,域被撤回一次,并且该方法的每一个可能的结束都会调用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();
}
}正如您所看到的,就我而言,这些后台线程确实正确地关闭了它们的领域实例。
发布于 2017-04-10 13:26:15
虽然我所有的后台任务确实都调用了realm.close(),但其中一个任务在它的生命周期中称它太晚了。那是我的GPSService,这是一个后台服务。问题是GPS服务在应用程序启动时初始化为Android服务,而Android服务很少被破坏。我正在注入一个领域实例onCreate并关闭它onDestroy。在@EpicPandaForce的评论之后,阅读他关于正确使用领域的文章。我意识到这是泄漏的原因。一个非活套线程在非常长的时间内一直保持一个开放的领域引用,因此,每次发生写事务时,mmap都会膨胀。现在,在每次服务运行时,我都会移动领域get/close,我的问题就解决了。
我的理解是,我们需要非常微妙地对待后台线程领域访问。谢谢你们的快速反应和帮助!
https://stackoverflow.com/questions/43144021
复制相似问题