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.
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
- Add to realmObjects when addChangeListener called * Only add the RealmObject to HandlerController.realmObjects when addChangeListener called. This will avoid we have too many objects in the map. ... — committed to realm/realm-java by beeender 8 years ago
- Add to realmObjects when addChangeListener called (#2723) * Only add the RealmObject to HandlerController.realmObjects when addChangeListener called. This will avoid we have too many objects in ... — committed to realm/realm-java by beeender 8 years ago
HandlerController.realmObjects
grows whenever aRealmObject
created which doesn’t make too much sense. I think we can put it into the map when at least one listener exists.