realm-java: Memory Leak leads to Crash

Sorry, I am not very sure whether this Crash is caused by Realm, but Android Studio Allocation Tracking shows relevant information with Realm, so I past the main code. Thanks!

Goal

Fix a Memory Leak bug

Expected Results

Fix

Actual Results

When the App is on the MainActivity (as bellow code) page, the memory is increased slowly, and then crashed.

screenshot from 2016-04-27 18-32-00

Steps & Code to Reproduce

Describe your current debugging efforts.

Code Sample

MainActivity.java


package top.honhe.server.activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ListView;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmResults;
import top.honhe.server.R;
import top.honhe.server.adapter.BedAdapter;
import top.honhe.server.event.PingBedResultEvent;
import top.honhe.server.model.Bed;
import top.honhe.server.utils.Ping;
import top.honhe.server.utils.SharePreferenceUtil;

public class MainActivity extends AppCompatActivity{
    private static final int PING_BEDTASK_PERIOD = 8000;
    private static final int PING_BEDTASK_DELAY = 5000;
    private ExecutorService fixedThreadPool;
    private EventBus eventBus;
    private Realm realm;
    private SharedPreferences.OnSharedPreferenceChangeListener prefListener;
    private TimerTask timerTask;
    private  Timer timer;
    private static final int MSG_MONITOR_BED = 1;
    private final int nThreads = 10;
    public RealmConfiguration realmConf;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case MSG_MONITOR_BED:
                    startPingBeds();
                    break;
                default:
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_monitor);
        initBedData();
        initEventBus();
    }
    @Override
    protected void onResume() {
        super.onResume();
        initThreadPool();
        eventBus.register(this);
        startMainBed();
    }
    private void initThreadPool() {
        fixedThreadPool = Executors.newFixedThreadPool(nThreads);
    }
    private void initEventBus() {
        eventBus = EventBus.getDefault();
    }
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(PingBedResultEvent event) {
        Log.d("TAG", event.getIp() + " is on: " + event.getisOn());
        realm.beginTransaction();
        realm.where(Bed.class).equalTo("id", event.getId()).equalTo("ip", event.getIp()).findFirst().setOn(event.getisOn());
        realm.commitTransaction();
    }
    private void initBedData() {
        realmConf = new RealmConfiguration.Builder(this)
                .name("Main_bed.realm")
                .inMemory()
                .build();
        realm = Realm.getInstance(realmConf);
        final RealmResults<Bed> bedRealmResults = realm.where(Bed.class).findAll();
        final BedAdapter bedAdapter = new BedAdapter(this, bedRealmResults);
        ListView listView = (ListView) findViewById(R.id.bedListView);
        listView.setAdapter(bedAdapter);
        realm.executeTransactionAsync(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                realm.where(Bed.class).findAll().deleteAllFromRealm();
                for (Map.Entry<String, Bed> entry : SharePreferenceUtil.getInstance().getBeds().entrySet()) {
                    realm.copyToRealm(entry.getValue());
                }
            }
        });
        setupBedOnChangeListener();
    }
    private void setupBedOnChangeListener() {
        prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
            public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
                String ip = prefs.getString(key, "");
                realm.beginTransaction();
                realm.where(Bed.class).equalTo("id", key).findFirst().setIp(ip);
                realm.commitTransaction();
            }
        };
        SharePreferenceUtil.getInstance().getSp().registerOnSharedPreferenceChangeListener(prefListener);
    }
    private void startPingBeds() {
        Log.d("StartPingBeds", "StartPingBeds");
        final RealmResults<Bed> bedRealmResults = realm.where(Bed.class).findAll();
        for (Bed bed : bedRealmResults) {
            startPingThread(new Bed(bed.getId(), bed.getIp()));
        }
    }
    private void startPingThread(final Bed bed) {
        fixedThreadPool.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    boolean isOn = Ping.ping(bed);
                    PingBedResultEvent pingBedResultEvent = new PingBedResultEvent();
                    pingBedResultEvent.setIp(bed.getIp());
                    pingBedResultEvent.setId(bed.getId());
                    pingBedResultEvent.setIsOn(isOn);
                    EventBus eventBus = EventBus.getDefault();
                    eventBus.post(pingBedResultEvent);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException();
                }
            }
        });
    }
    private void startMainBed() {
        startMainBedTimerTask();
    }
    private void startMainBedTimerTask() {
        timer = new Timer();
        timerTask = new TimerTask() {
            @Override
            public void run() {
                Message message = new Message();
                message.what = MSG_Main_BED;
                handler.sendMessage(message);
            }
        };
        timer.schedule(timerTask, PING_BEDTASK_DELAY, PING_BEDTASK_PERIOD);
    }
    @Override
    protected void onStop() {
        super.onStop();
        fixedThreadPool.shutdown();
        eventBus.unregister(this);
        timer.cancel();
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        realm.removeAllChangeListeners();
        SharePreferenceUtil.getInstance().getSp().unregisterOnSharedPreferenceChangeListener(prefListener);
    }
}

Ping.java


package top.honhe.server.utils;
import java.io.IOException;
import top.honhe.server.model.Bed;

public class Ping {
    public static boolean ping(Bed bed){
        Runtime runtime = Runtime.getRuntime();
        boolean isOn;
        try
        {
            Process  mIpAddrProcess = runtime.exec("/system/bin/ping -c 1 -W 2 " + bed.getIp());
            int mExitValue = mIpAddrProcess.waitFor();
//            Log.d("Ping", " mExitValue "+mExitValue);
            if(mExitValue==0){
                isOn = true;
            }else{
                isOn = false;
            }
            return isOn;
        }
        catch (InterruptedException ignore)
        {
            ignore.printStackTrace();
            System.out.println(" Exception:"+ignore);
        }
        catch (IOException e)
        {
            e.printStackTrace();
            System.out.println(" Exception:"+e);
        }
        return false;
    }
}

Version of Realm and tooling

Realm version(s): 0.89.1

Android Studio version: 2.0

Which Android version and device: 4.x, 5.x

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 15 (9 by maintainers)

Commits related to this issue

Most upvoted comments

HandlerController.realmObjects grows whenever a RealmObject created which doesn’t make too much sense. I think we can put it into the map when at least one listener exists.