I'm using Realm 2.4.3
in a large iPad Application for one of our customer.
Most of the time Realm
performed very well, but now the number of Records is increasing and a get some memory issues.
App
- Deployment Target: 10.0
- BaseSDK: 10.2
- iPad only
- Realm 2.4.3
- The App was designed to work offline, thats why we use Realm for local storage
- There are some methods which syncs Data from a Backend via HTTP to the Realm Database and vice versa.
- Number of Records in Realm Database
(unexpected) behaviour
- the realm file size growth above 2,5GB (with compact fix from below ~500KB)
- realm tries to load the whole file into memory
- iPad Air 2 (2GB) crashes, on iPad Pro (4GB) everything works well
Issues i already read
- mmap() failed: Cannot allocate memory
https://github.com/realm/realm-cocoa/issues/1159 - mmap() failed: Cannot allocate memory size
https://github.com/realm/realm-cocoa/issues/3226 - 'RLMException', reason: 'mmap() failed: Cannot allocate memory size: 1207959552'
https://github.com/realm/realm-cocoa/issues/3920
The fix I tried
the writeCopyToURL:encryptionKey:error:
compact hack
I have a Singleton Object which handles all storage actions to realm,
which has a writeTransaction:
method which handles beginWriteTransaction
and commitWriteTransaction
handling. All storage actions are coming through this method.
- (void)writeTransaction:(void (^)(void))block
{
[self _ensureRealmThread:^{
NSDate *startDate = [NSDate date];
[[self _defaultRealm] beginWriteTransaction];
block();
NSError *commitWriteTransactionError = nil;
[[self _defaultRealm] commitWriteTransaction:&commitWriteTransactionError];
if (commitWriteTransactionError) {
NSLog(@"commit error: %@", commitWriteTransactionError);
}
NSTimeInterval time = [[NSDate date] timeIntervalSinceDate:startDate];
if (time > 0.5) {
NSLog(@"WARNING: Transaction duration > 0.5");
}
// i added these 5 lines to compact the database every 2000 requests
_writeTransactionIndex++;
if (_writeTransactionIndex > 2000) {
_writeTransactionIndex = 0;
[self compactDatabase];
}
}];
}
- (void)compactDatabase
{
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *documentsPath = searchPaths[0];
NSString *defaultCompactPath = [documentsPath stringByAppendingPathComponent:@"defaultCompact.realm"];
NSURL *defaultCompactURL = [NSURL fileURLWithPath:defaultCompactPath];
// remove old
if ([[NSFileManager defaultManager] fileExistsAtPath:[defaultCompactURL path]]) {
[[NSFileManager defaultManager] removeItemAtURL:defaultCompactURL
error:nil];
}
NSError *writeError = nil;
[[self _defaultRealm] writeCopyToURL:defaultCompactURL
encryptionKey:nil
error:&writeError];
if (!writeError) {
[[NSFileManager defaultManager] replaceItemAtURL:[self _defaultRealm].configuration.fileURL
withItemAtURL:defaultCompactURL
backupItemName:nil
options:NSFileManagerItemReplacementUsingNewMetadataOnly
resultingItemURL:nil
error:nil];
}
}
The fix works in the storage!! The file shrinks from 2,5GB to 500KB. But i still got the issue that realm wants to allocate too much memory:
commit error: Error Domain=io.realm Code=9 "mmap() failed: Cannot allocate memory size: 268435456 offset: 2952790016" UserInfo={NSLocalizedDescription=mmap() failed: Cannot allocate memory size: 268435456 offset: 2952790016, Error Code=9}
Is there somebody with an idea to fix this ? :-)
If i missed some necessary information please leave a comment.. i'm in this issue for several days and my brain is like 💥
compactDatabase
? – Ping