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(); 
    } 
    } 

通话正如你可以看到,这些背景线程确实关闭他们的领域实例,就我而言。

+0

'和0-3其他线程(背景作业)的其他参考.'我很确定“后台作业”不关闭他们的领域。 – EpicPandaForce

+0

@EpicPandaForce他们关闭了他们的领域。我编辑了我的问题,并添加了我的后台作业的领域开放/关闭逻辑。 –

+0

@EpicPandaForce我想认为我不那么愚蠢。我已经有了这个问题超过2个星期,并一直试图解决它。确保我所有领域的实例都关闭是我做的第一件事。我必须在更大规模上做错事。 –

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

我带走的是一个需要非常精细地对待后台线程领域访问。谢谢你们的快速反应和帮助!