RealmError:Realm内存不足
我使用Realm 3.0.0作为我的Android应用程序的数据库。这就像一个问卷调查应用程序,用户在应用程序内导航很多。当我使用的应用程序(来回)不断,我得到以下错误:RealmError:Realm内存不足
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
上获得Realm实例,并在onDestroy
上关闭它。还有其他后台网络作业可用于上载获取Realm实例的数据。这些作业在完成运行或取消时会关闭它们的Realm实例。
所有上述的经由匕首2得到他们的领域实例直通注射:
@Provides
@Nullable
static Realm realm(@Nullable RealmConfiguration configuration) {
if (configuration != null) {
Realm.setDefaultConfiguration(configuration);
return Realm.getDefaultInstance();
}
return null;
}
配置也以相同的匕首模块提供。
更具体地说,调查问卷包含ViewPager中显示的很多问题片段。每个片段被注入一个领域。给定Question Fragment中的许多交互将数据写入数据库(某些异步,某些阻止)。这些片段还会查询onResume
上的数据库以获取其更新的数据。其中一些数据也通过realm.copyFromRealm()
从Realm中复制出来。现在,在这些情况发生的任何时候,上传作业最有可能运行,并从数据库读取数据并将其上传到服务器。上传作业完成后,它会写入数据库。
我想我可以有多达7-12片段/活动在给定时刻在UI线程上持有领域引用。以及0-3其他线程(Background Jobs)上的其他参考。
此外,我在每次应用程序发布时通过Realm.compactRealm(realmConfiguration)
压缩我的领域数据库(可能作为一个单独的问题,这似乎并不能完成它的工作)。
上面我试图用描述性的描述我的领域用法,而没有深入细节。现在我的问题是,当用户过度使用应用程序(在活动/片段之间来回切换(realm注入+数据库读取查询),上传数据(realm注入+数据库读取&写入查询)),我得到以上贴出内存错误。
我也在使用泄漏金丝雀,它没有检测到任何泄漏。 (不知道它是否可以)
我是否以不应该使用Realm的方式?我应该关闭Realm实例而不是onDestroy
?我应该在一个活动中只有一个领域实例,并且拥有所有它的特性(在我的情况下最多5个)使用此实例?我可以在我的应用程序中做出什么样的更改,也许我的应用程序体系结构可以解决此问题?
我很感谢任何帮助,试图解决这个问题。
编辑:我在我的后台线程中共享领域开放关闭逻辑。
我所有的作业都将共享相同的领域使用,这是如下: 境界是通过注射懒洋洋地:
@Inject protected transient Lazy<Realm> lazyRealm;
境界对象引用在private transient Realm realm;
场举行。我正在使用Android Priority Job Queue。当作业被添加:
@Override
public void onAdded() {
realm = lazyRealm.get();
realm.executeTransaction(realm1 -> {
//write some stuff into realm
});
realm.close();
}
和作业程序运行时的境界是retreived一次,这种方法的每一种可能的结局有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();
}
}
通话正如你可以看到,这些背景线程确实关闭他们的领域实例,就我而言。
虽然我所有的后台任务都确实调用了realm.close()
,但其中一个人在生命周期中称它为时已晚。那是我的GPSService,这是一个后台服务。问题在于GPS服务在应用程序作为Android服务启动时初始化,这很少被破坏。我正在注入领域实例onCreate
并关闭它onDestroy
。在@EpicPandaForce的评论之后,阅读他关于正确使用领域的文章。我意识到这是泄漏的原因。一个非循环线程在很长的时间内保持开放的领域参考,因此,每次发生写事务时mmap
都在膨胀。现在,每当服务运行时,我都会将领域的接近/移近发生,我的问题已得到解决。
我带走的是一个需要非常精细地对待后台线程领域访问。谢谢你们的快速反应和帮助!
'和0-3其他线程(背景作业)的其他参考.'我很确定“后台作业”不关闭他们的领域。 – EpicPandaForce
@EpicPandaForce他们关闭了他们的领域。我编辑了我的问题,并添加了我的后台作业的领域开放/关闭逻辑。 –
@EpicPandaForce我想认为我不那么愚蠢。我已经有了这个问题超过2个星期,并一直试图解决它。确保我所有领域的实例都关闭是我做的第一件事。我必须在更大规模上做错事。 –