Realm-java: [Crash] Unrecoverable error. mmap() failed: Out of memory size ?

Created on 3 Feb 2018  Â·  7Comments  Â·  Source: realm/realm-java

Hello guys,

Every second I send the event to the server and save to the realm after a long time without turning off the application will be crash. ( about 1 or 2 days)

How to solve this problem?
Thanks.

P.s:
I think this might be due to running out of RAM or Storage device ?
But after a day, I will call the function to delete the event successfully.

Version of Realm and tooling

Realm version(s): 4.0.0

Realm sync feature enabled: no
Android Studio version: 3.0.1

Which Android version and device: Android 5.0, Jacs/ Zenfone 3 Max

Code :
Background Event

public class BackgroundEventService extends Service {

    public Context context = this;
    public Handler handler = null;
    public static Runnable runnable = null;
    public final int timeDelayed = 5000; // default 
    // Config.getInstance().getTransmissionFrequencyToSecond() = 1s
    public static boolean isServiceRunning = false;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        handler = new Handler();
        runnable = new Runnable() {
            public void run() {
                if (hasConfig()) {
                    EventRepository.getInstance().addRawEvent();
                    handler.postDelayed(runnable, Config.getInstance().getTransmissionFrequencyToSecond());
                } else {
                    handler.postDelayed(runnable, timeDelayed);
                }
            }
        };
        if (hasConfig()) {
            handler.postDelayed(runnable, Config.getInstance().getTransmissionFrequencyToSecond());
        } else {
            handler.postDelayed(runnable, timeDelayed);
        }

    }

    public boolean hasConfig() {
        if (Config.getInstance().getTransmissionFrequencyToSecond() != 0)
            return true;
        return false;
    }

    @Override
    public void onDestroy() {
        if (handler!=null && runnable!=null) {
            handler.removeCallbacks(runnable);
        }
        isServiceRunning = false;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        isServiceRunning = true;
        return START_NOT_STICKY;
    }
}

Func of this line : EventRepository.getInstance().addRawEvent();

public void addRawEvent() {
        final RawEvent event = new RawEvent();
        event.setDevId(Integer.valueOf(DeviceModeDB.getInstance().getDevID()));
        event.setBusId(BusManager.getInstance().getCurrentDriver().getBusID());
        event.setLatitude(BusManager.getInstance().getLatitude());
        event.setLongitude(BusManager.getInstance().getLongitude());
        event.setEventName(EventName.RAW_EVENT.name());
        event.setEventTime(TimeUtils.generateTime());
        EventDB.saveRawEvent(event, new Realm.Transaction.OnSuccess() {
            @Override
            public void onSuccess() {
                addRawEvent(event, false);
            }
        });
    }

    private void addRawEvent(final RawEvent event, final boolean inBackground) {
        if (event == null) return;
        event.setEventSend(TimeUtils.generateTime());
        mService.addRawEvent(event).enqueue(new Callback<EventResult>() {
            @Override
            public void onResponse(Call<EventResult> call, Response<EventResult> response) {
                if (response.isSuccessful() && response.body() != null && response.body().onSuccess()) {
                    if (inBackground) {
                        EventDB.saveRawEventBackground(event);
                    } else {
                        EventDB.saveRawEvent(event, null);
                    }
                }
            }

            @Override
            public void onFailure(Call<EventResult> call, Throwable t) {

            }
        });
    }

EventDB : Save to Realm

public static void saveRawEvent(final RawEvent item, final Realm.Transaction.OnSuccess onSuccess) {
        if (item == null) return;
        Realm.getDefaultInstance().executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.insertOrUpdate(item);
            }
        }, new Realm.Transaction.OnSuccess() {
            @Override
            public void onSuccess() {
                if (onSuccess != null) {
                    onSuccess.onSuccess();
                }
            }
        });
    }

    public static void saveRawEventBackground(final RawEvent item) {
        if (item == null) return;
        Realm.getDefaultInstance().executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.insertOrUpdate(item);
            }
        });
    }

Init Realm

public class ApplicationController extends MultiDexApplication {

    private static ApplicationController mInstance;

    public ApplicationController() {

    }

    public static ApplicationController getInstance() {
        return mInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
        init();
    }

    private void init() {
        if (!BuildConfig.DEBUG) {
            Fabric.with(this, new Crashlytics());
        }
        Realm.init(this);
        RealmConfiguration config = new RealmConfiguration.Builder()
                .compactOnLaunch()
                .build();
        Realm.compactRealm(config);
    }
}

Gradle :

buildscript {
    repositories {
        jcenter()
        maven { url 'https://maven.google.com' }
        maven {
            url "https://jitpack.io"
        }

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath "io.realm:realm-gradle-plugin:4.0.0"
        classpath 'com.google.gms:google-services:3.1.1' // google-services plugin
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven {
            url 'https://maven.google.com'
        }
        maven {
            url "https://jitpack.io"
        }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
project.ext {
    appcompat = "26.0.1"
    retrofit = "2.3.0"
    butterknife = "8.8.1"
    rxjava = "2.1.3"
    rxandroid = "2.0.1"
}

buildscript {
    repositories {
        maven { url 'https://maven.fabric.io/public' }
    }

    dependencies {
        // These docs use an open ended version so that our plugin
        // can be updated quickly in response to Android tooling updates

        // We recommend changing it to the latest version from our changelog:
        // https://docs.fabric.io/android/changelog.html#fabric-gradle-plugin
        classpath 'io.fabric.tools:gradle:1.+'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
apply plugin: 'realm-android'

repositories {
    maven { url 'https://maven.fabric.io/public' }
    maven { url 'https://maven.google.com' }
}

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.2"
    defaultConfig {
        applicationId "com.myapp.event"
        minSdkVersion 21
        targetSdkVersion 26
        versionCode 86
        versionName "6.2"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    realm {
        syncEnabled = true
    }
    configurations.all {
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.2'
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile "com.android.support:appcompat-v7:$project.appcompat"
    compile "com.squareup.retrofit2:retrofit:$project.retrofit"
    compile "com.squareup.retrofit2:converter-gson:$project.retrofit"
    compile "com.squareup.retrofit2:adapter-rxjava2:$project.retrofit"
    compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    testCompile 'junit:junit:4.12'
    compile 'com.google.code.gson:gson:2.8.2'
    compile "io.reactivex.rxjava2:rxjava:$project.rxjava"
    compile "io.reactivex.rxjava2:rxandroid:$project.rxandroid"
    compile('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
        transitive = true
    }
    compile "com.jakewharton:butterknife:$project.butterknife"
    annotationProcessor "com.jakewharton:butterknife-compiler:$project.butterknife"
    compile 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
    compile 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar'
    testCompile 'junit:junit:4.12'
    compile 'de.hdodenhof:circleimageview:2.1.0'
    compile 'me.relex:circleindicator:1.2.2@aar'
    compile 'com.github.bumptech.glide:glide:4.3.1'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.3.1'
    compile 'org.greenrobot:eventbus:3.1.1'
    compile "com.jakewharton:butterknife:$project.butterknife"
    annotationProcessor "com.jakewharton:butterknife-compiler:$project.butterknife"
    compile 'pl.bclogic:pulsator4droid:1.0.3'
    compile 'net.zetetic:android-database-sqlcipher:3.5.9@aar'
    compile 'com.github.pwittchen:reactivenetwork-rx2:0.12.1'
    compile 'com.yqritc:recyclerview-flexibledivider:1.4.0'
    compile files('libs/gpx-parser-1.2.jar')
    compile 'com.google.android.gms:play-services-maps:11.8.0'
    compile 'com.google.firebase:firebase-core:11.8.0'
    compile 'com.google.firebase:firebase-database:11.8.0'
    compile 'com.android.support:multidex:1.0.2'
    compile 'com.github.safetysystemtechnology:location-tracker-background:v1.3'
    compile 'com.jenzz.appstate:appstate:3.0.1'
}
apply plugin: 'com.google.gms.google-services'

Log:

E/AndroidRuntime(21138): io.realm.exceptions.RealmError: Unrecoverable error. mmap() failed: Out of memory size: 1342177280 offset: 0 in /Users/cm/Realm/realm-java/realm/realm-library/src/main/cpp/io_realm_internal_SharedRealm.cpp line 101

E/AndroidRuntime(21138):         at io.realm.internal.SharedRealm.nativeGetSharedRealm(Native Method)

E/AndroidRuntime(21138):         at io.realm.internal.SharedRealm.<init>(SharedRealm.java:194)

E/AndroidRuntime(21138):         at io.realm.internal.SharedRealm.getInstance(SharedRealm.java:241)

E/AndroidRuntime(21138):         at io.realm.internal.SharedRealm.getInstance(SharedRealm.java:231)

E/AndroidRuntime(21138):         at io.realm.BaseRealm.compactRealm(BaseRealm.java:636)

E/AndroidRuntime(21138):         at io.realm.Realm.compactRealm(Realm.java:1689)

E/AndroidRuntime(21138):         at com.myapp.event.ApplicationController.init(ApplicationController.java:103)

E/AndroidRuntime(21138):         at com.myapp.event.ApplicationController.onCreate(ApplicationController.java:87)

E/AndroidRuntime(21138):         at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1012)

E/AndroidRuntime(21138):         at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4557)

E/AndroidRuntime(21138):         at android.app.ActivityThread.access$1500(ActivityThread.java:151)

E/AndroidRuntime(21138):         at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)

E/AndroidRuntime(21138):         at android.os.Handler.dispatchMessage(Handler.java:102)

E/AndroidRuntime(21138):         at android.os.Looper.loop(Looper.java:135)

E/AndroidRuntime(21138):         at android.app.ActivityThread.main(ActivityThread.java:5258)

E/AndroidRuntime(21138):         at java.lang.reflect.Method.invoke(Native Method)

E/AndroidRuntime(21138):         at java.lang.reflect.Method.invoke(Method.java:372)

E/AndroidRuntime(21138):         at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:940)

E/AndroidRuntime(21138):         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:735)

Most helpful comment

I prefer

try(Realm realm = Realm.getDefaultInstance()) {
    // do something
}

or

Realm.getDefaultInstance().use { realm ->
    // do something
}

All 7 comments

Because you open a new Realm instance for every single thread that ever calls saveRawEventBackground or saveRawEvent, and you NEVER close them.

@Zhuinden
1.The current solution is to use eventBus to send the event to the main thread and then use the saveRawEventBackground or saveRawEvent to save it.
Is that solve this problem without close realm?

2.If I delete the old data every 12 hours, the realm automatically reduce the size?

Thanks.

No, deleted objects would still take up empty space because the old versions that are left unclosed would still retain them.

Also "unclaimed" empty state is reused by future writes, but only gets shrunk down if Realm is compacted (which requires that there are 0 open Realms on any thread)

Realm.getDefaultInstance().blah

This construct doesn't allow you to close the Realm.

You can verify number of open global instances and number of open thread-local (on current thread) instances with Realm.getGlobal/LocalInstanceCount.

Thanks @Zhuinden .

@Zhuinden Let say I have globalInstanceCount = 5; then how can I close all realm?

@Zhuinden :

Realm realm = Realm.getDefaultInstance();
// do something
realm.close();

I prefer

try(Realm realm = Realm.getDefaultInstance()) {
    // do something
}

or

Realm.getDefaultInstance().use { realm ->
    // do something
}
Was this page helpful?
0 / 5 - 0 ratings