3

I have implemented Realm as my DB, and in my app I run a service on the phone contacts for checking any change in my phonebook. The service works for like 3 to 4 changes and then the app crashes with this error in my logcat.

Unrecoverable error. mremap(): failed: Out of memory in io_realm_internal_SharedGroup.cpp line 188

Here's my code:

 public static void refreshingContactsDB()
{


        createCountryDetailsArrayModel();

        TelephonyManager tm = (TelephonyManager) ApplicationController.getInstance()
                .getSystemService(Context.TELEPHONY_SERVICE);
        String simCountryISO = tm.getSimCountryIso();

        for (int i = 0; i < countryDetailsList.size(); i++) {
            if (simCountryISO.equalsIgnoreCase(countryDetailsList.get(i)
                    .getCode())) {

                dialCodePrefix = countryDetailsList.get(i).getDial_code();

            }
        }


        AppPreferenceManager.getInstance().setContactUpdate(false);

        Logger.debug("Contact Update Refreshing Contact Started -->");

        Thread background = new Thread(new Runnable() {
            public void run() {

                Realm realmRefresh = Realm.getInstance(ApplicationController.getInstance());
                ContentResolver cr = ApplicationController.getInstance()
                        .getContentResolver();

                Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);

                String duplicateName = "";
                String duplicatePhone = "";

                if (phones.getCount() > 0) {

                    final int nameIndex = phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
                    final int numberIndex = phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);

                    while (phones.moveToNext()) {
                        String name = phones.getString(nameIndex);
                        String phoneNo = phones.getString(numberIndex);

                        if (phoneNo != null && !phoneNo.isEmpty()) {

                            phoneNo = phoneNo.replace(" ", "");
                            phoneNo = phoneNo.replace("(", "");
                            phoneNo = phoneNo.replace(")", "");
                            phoneNo = phoneNo.replace("-", "");
                            phoneNo = phoneNo.replace("\u00a0", "");
                            phoneNo = phoneNo.replace("\u202c", "");
                            phoneNo = phoneNo.replace("\u2011", "");
                            phoneNo = phoneNo.replace("\u202a", "");
                            phoneNo = phoneNo.replace("*", "");
                            phoneNo = phoneNo.replace("#", "");

                            if (phoneNo.length() >= 5) {

                                if (name.equalsIgnoreCase(duplicateName) && phoneNo.equalsIgnoreCase(duplicatePhone)) {
                                    continue;
                                }

                                duplicateName = name;
                                duplicatePhone = phoneNo;

                                String formattedPhoneNumber;
                                formattedPhoneNumber = parseNumber(phoneNo);

                                //                                List<LocalContactDb> getContactsList = Select
                                //                                        .from(LocalContactDb.class)
                                //                                        .where(Condition.prop("PHONE").eq(
                                //                                                formattedPhoneNumber))
                                //                                        .list();
                                RealmResults<R_LocalContactDB> realmResults = realmRefresh.where(R_LocalContactDB.class).equalTo("phone", formattedPhoneNumber).findAll();
                                Logger.debug("Size: " + realmResults.size());
                                RealmResults<R_LocalContactDB> query = realmRefresh.where(R_LocalContactDB.class).findAll();
                                R_LocalContactDB rContacts = new R_LocalContactDB(null, null, false, 0);


                                if (realmResults.size() == 0) {
                                    realmRefresh.beginTransaction();
                                    R_LocalContactDB rCont = realmRefresh.copyToRealm(rContacts);
                                    rCont.setName(name);
                                    rCont.setPhone(formattedPhoneNumber);
                                    rCont.setStatus(0);
                                    rCont.setMatchedWithRecent(true);
                                    Logger.debug("New Size: " + query.size());
                                    realmRefresh.commitTransaction();

                                    Logger.debug("Contact Update " + name
                                            + " saved");
                                } else {
                                    realmRefresh.beginTransaction();
                                    if (!name.equalsIgnoreCase(realmResults.get(0).getName())) {
                                        realmResults.get(0).setName(name);
                                    }

                                    realmResults.get(0).setMatchedWithRecent(true);
                                    // realmResults.get(0);
                                    Logger.debug("New Size Else Condition: " + query.size());
                                    realmRefresh.commitTransaction();
                                    realmRefresh.close();


                                }

                            }


                        }

                    }
                    ContactsSyncService.contactUpdated= false ;

                    phones.close();


                }

                deleteExtraContacts();

                getNumbersFromDBAndUpdate();

            }

        });
        background.start();
    }

I have read this, but can't seem to understand it fully from the documentation:

Please note that writes block each other, and will block the thread they are made on if other writes are in progress. This can cause ANR errors if you are doing writes from the UI thread while also doing writes from a background thread. To avoid this, first create objects in memory first outside a transaction, and only perform a simple Realm.copyToRealm() inside the transaction, which will keep blocking times to a minimum.

1 Answers1

2

You are most likely running out of memory because you are calling Realm.getInstance() in your parseContactstoContactsDB-thread without closing it again.

Because you are creating a new thread each time you call that method, you are effectively opening a completely new Realm each time which takes up a non-trivial amount of memory.

Calling realm.close() before exiting the thread should free those resources again and prevent you from running out of memory.

Christian Melchior
  • 19,978
  • 5
  • 62
  • 53