我在一个大型iPad应用程序中为我们的一个客户使用Realm 2.4.3
大多数时候Realm
表现得非常好,但现在记录的数量正在增加并且会产生一些内存问题。
writeCopyToURL:encryptionKey:error:
紧凑型黑客
我有一个Singleton对象可以处理所有存储操作,
它具有处理writeTransaction:
和beginWriteTransaction
处理的commitWriteTransaction
方法。所有存储操作都是通过此方法实现的。
- (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];
}
}
修复工作在存储!!该文件从2.5GB缩小到500KB。 但我仍然遇到领域想要分配太多内存的问题:
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}
有人有想法解决这个问题吗? :-)
如果我错过了一些必要的信息,请发表评论..我在这个问题上好几天,我的大脑就像
答案 0 :(得分:1)
我们遇到此错误。在Realm解决问题之前,以下是我们的解决方法:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_SERIAL, 0), ^{
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.schemaVersion = [schema intValue];
config.shouldCompactOnLaunch = ^BOOL(NSUInteger totalBytes, NSUInteger usedBytes){
// totalBytes refers to the size of the file on disk in bytes (data + free space)
// usedBytes refers to the number of bytes used by data in the file
// Compact if the file is over 50MB in size and less than 50% 'used'
NSUInteger oneHundredMB = 50 * 1024 * 1024;
return (totalBytes > oneHundredMB) && (usedBytes / totalBytes) < 0.5;
};
__block BOOL deleteRealm = false;
//schema has changed. Set delete flag.
config.migrationBlock = ^(RLMMigration *migration, uint64_t oldSchemaVersion) {
if (oldSchemaVersion < [schema intValue]) {
deleteRealm = TRUE;
}
};
[RLMRealmConfiguration setDefaultConfiguration:config];
//*** Memory Allocation bug 'fix/hack' ***
// Put realm init in try block. If it fails, blow it away in catch block. Then the following realm init will work.
// This fix eliminated the error for us, with no effect on perfomance.
@try
{
[RLMRealm defaultRealm];
}
@catch(...) {
NSURL *rurl = [RLMRealmConfiguration defaultConfiguration].fileURL;
// blow the database clean
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtURL:rurl error:&error];
if(error) {
NSLog(@"error %@ removing realm db", error);
} else {
NSLog(@"removed realm db successfully!");
}
}
[RLMRealm defaultRealm];
if (deleteRealm){
[[RLMRealm defaultRealm] beginWriteTransaction];
[[RLMRealm defaultRealm] deleteAllObjects];
[[RLMRealm defaultRealm] commitWriteTransaction];
deleteRealm = FALSE;
}
});