Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'RLMException', reason: 'mmap() failed #620

Closed
syedhali opened this issue Jul 19, 2014 · 4 comments
Closed

'RLMException', reason: 'mmap() failed #620

syedhali opened this issue Jul 19, 2014 · 4 comments
Labels

Comments

@syedhali
Copy link

This is such a wonderful framework! Thank you guys so much for open sourcing this.

I've been using running into this exception quite frequently.

*** Terminating app due to uncaught exception 'RLMException', reason: 'mmap() failed: Cannot allocate memory'
*** First throw call stack:
(0x189af6f50 0x1960001fc 0x1000cbc40 0x1000cbe2c 0x1000cb00c 0x1000cac90 0x1000ca9e0 0x1000a15c4 0x18cac0670 0x18cac03f4 0x1000ad074 0x1000ac7d8 0x18cac0670 0x18cac03f4 0x18cac77a4 0x18cb36368 0x1000b59e0 0x1000b565c 0x18cb3455c 0x18cb33f08 0x18cb2d9ec 0x18cac18cc 0x18cac0ad0 0x18cb2d044 0x18f6df504 0x18f6df030 0x189ab6e90 0x189ab6df0 0x189ab5014 0x1899f5c20 0x18cb2c1c8 0x18cb26fdc 0x1000b5c64 0x1965f3aa0)
libc++abi.dylib: terminating with uncaught exception of type NSException

Any ideas why the mmap operation can't allocate enough memory?

@jpsim
Copy link
Contributor

jpsim commented Jul 19, 2014

By curiosity, how much data are you trying to mmap? i.e. how large is your realm file on disk?

@syedhali
Copy link
Author

Hey @jpsim, thanks for the quick response!

It looks like the realm file gets into some kind of locked state and keeps growing larger and larger while I'm inspecting it.
Started: 25KB
Reload same data (update or insert): 122KB
Keep loading page over and over (update or insert): 500KB
More (update or insert): 2MB
More: 12.6MB
More: 25.2MB
After 25.2MB it keeps climbing by itself (the app is not running) until it reached ~300MB (I deleted it at that point). I've attached some screenshots of the realm files I would download from the app bundle and inspect.

screen shot 2014-07-19 at 12 50 03 am
screen shot 2014-07-19 at 1 00 10 am
screen shot 2014-07-19 at 1 00 27 am
screen shot 2014-07-19 at 1 01 12 am

A little more context:

I'm importing the JSON into models (using an APIObject wrapped via CottonObject) in a background thread, each model has its own write transaction, and when the import is done I execute a completion block with the data on the main thread like this:

+ (User*) userWithAPIUser:(APIUser*)apiUser wrapTransaction:(BOOL)wrapTransaction
{
    // get the default realm and try to find a user to update (else import new)
    RLMRealm* realm = [RLMRealm defaultRealm];
    User* user = nil;
    RLMArray* matchingUsers = [User objectsWhere:@"id == %@",apiUser.id];

    // write the user to the database
    wrapTransaction ? [realm beginWriteTransaction] : 0;
    user = matchingUsers.count ? matchingUsers.firstObject : [[User alloc] init];
    user.id = apiUser.id.integerValue;
    user.email = apiUser.email;
    user.first_name = apiUser.first_name;
    user.last_name = apiUser.last_name;
    user.token = apiUser.token;
    [realm addObject:user];
    wrapTransaction ? [realm commitWriteTransaction] : 0;

    // return the cached user
    return user;
}

+ (NSArray*) usersWithAPIUsers:(NSArray*)apiUsers wrapTransaction:(BOOL)wrapTransaction
{
    NSMutableArray* users = [NSMutableArray array];
    for (APIUser* apiUser in apiUsers)
    {
        User* user = [User userWithAPIUser:apiUser wrapTransaction:wrapTransaction];
        [users addObject:user];
    }
    return users;
}

+ (void) usersWithAPIUsers:(NSArray*)apiUsers
                 wrapTransaction:(BOOL)wrapTransaction
                      completion:(void(^)(NSArray* users))complete
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
    {
        NSArray* users = [User usersWithAPIUsers:apiUsers wrapTransaction:wrapTransaction];
        if (complete)
        {
            dispatch_async(dispatch_get_main_queue(), ^
            {
                complete(users);
            });
        }
    });
}

I've browsed the schema via the Realm Browser and there aren't any duplicate entities either (the ones that exist just get updated). I apologize if I'm doing anything horribly wrong here, I'm more of an audio guy :P

@alazier
Copy link
Contributor

alazier commented Jul 23, 2014

Are you running this code passing int YES or No to wrapTransaction? If you are constantly running through inserts/updates without ever closing a transaction you will end up using a huge amount of temporary disk space which will not get reclaimed until the transaction is closed. This might also explain the mmap issue. If you are using a single outer transaction (NO for wrapTransaction) then try passing in YES for wrapTransaction to see if that changes the behavior. I would also suggest using a single transaction in usersWithAPIUsers:wrapTransaction: around each group of users rather than using a transaction for each user.

Also, when you dispatch back to the main queue, you are passing an array of RLMObjects which are associated with the RLMRealm instance on the background queue. There isn't currently a way to share objects across RLMRealm instances/threads so for now you need fetch the objects on the main thread after a change. Instead of dispatching back to the main thread you can instead register for a notification and respond in kind to any changes.

@timanglade
Copy link
Contributor

This was probably related to #709 which we fixed earlier this morning, per the ML

@bmunkholm bmunkholm added the bug label Aug 13, 2014
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

5 participants