ios - Realm :mmap() 失败:无法分配内存大小

标签 ios objective-c ipad realm mmap

我正在为我们的一位客户在大型 iPad 应用程序中使用 Realm 2.4.3
大多数时候 Realm 表现得很好,但现在 Records 的数量在增加并且出现一些内存问题。

应用

  • 部署目标:10.0
  • BaseSDK:10.2
  • 仅限 iPad
  • Realm 2.4.3
  • 该应用程序专为离线工作而设计,这就是我们使用 Realm 进行本地存储的原因
  • 有一些方法可以通过 HTTP 将数据从后端同步到 Realm 数据库,反之亦然。
  • Realm 数据库 Number of Records 中的记录数

(意外)行为

  • realm 文件大小增长超过 2.5GB(压缩修复低于 ~500KB)
  • realm 尝试将整个文件加载到内存中
  • iPad Air 2 (2GB) 崩溃,在 iPad Pro (4GB) 上一切正常

我已经读过的问题

我尝试过的修复

writeCopyToURL:encryptionKey:error: 紧凑黑客

我有一个单例对象,它处理所有存储到 Realm 的操作, 它有一个 writeTransaction: 方法来处理 beginWriteTransactioncommitWriteTransaction 处理。所有存储操作都通过此方法进行。

- (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。 但是我仍然遇到 Realm 想要分配太多内存的问题:

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}

有人有办法解决这个问题吗? :-)
如果我错过了一些必要的信息,请发表评论。我在这个问题上已经好几天了,我的大脑就像💥

最佳答案

我们遇到了这个错误。在 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;
    }
});

关于ios - Realm :mmap() 失败:无法分配内存大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42527836/

相关文章:

ios - 如何防止表格 View 在键盘启动时不选择单元格

ios - 未检测到 SpriteKit 碰撞

ios - 如何将 CoreData 表与在线资源同步?

iphone - 使用无效 key 时返回错误的解密文本

iphone - 使用 NSFetchedResultsController 进行分页?

ios - ios 中 cornerradius 中的段控制问题

ios - iPhone和iPad的iOS图像大小

ios - TodayWidget 构建正确但 com.apple.springboard 正在运行

objective-c - 可以在 NSUserDefaults 中保留 HKQueryAnchor 吗?

python - 如何在 Python 中遍历以日语命名的目录?