はじめに
趣味で作っているアプリでrealm-javaを使っているのですが、タイトルの通りFatal signal 11で落ちることがあったのでメモ。
なお、根本的な解決策および原因は分かってません。もうちょっと条件がはっきり分かったらissueに書こうかとも思うのですが、Debugでステップ実行してると発生しなかったりで発生箇所すらはっきりしないのです。。。
ちなみに、本現象は執筆時点で最新の0.79.1でも発生しています。
発生した現象と状況
Realm
を今回実装したServiceのプライベートなフィールドとして定義、onCreate
で初期化してサービス内で引き回して、最終的にonDestroy
で破棄する作りとしていた。
Realm mRealm;
@Override
public void onCreate() {
mReam = Realm.getInstance(this);
}
@Override
public void onDestroy() {
mRealm.close();
}
また、コード中ではRealmResult
もプライベートなフィールドとして各所に引き回していました。
RealmResult<Hoge> mRealmResult;
private void getHogeList(String hoge) {
return mRealmResult.where().equalTo("hoge", hoge).findAll();
}
private void getHogeHogeList(String hogehoge) {
return mRealmResult.where().equalTo("hogehoge", hogehoge).findAll();
}
なぜこのような作りにしていたかと言うと、ユーザの操作によってカラムhoge
で絞り込んだ結果をユーザに提示。
そこから更にユーザ操作でカラムhogehoge
に対して絞り込み条件を追加という処理を行っていたから。
realmではRealmResult
に対してもクエリーを投げられるので、結果に対してさらに絞り込みという処理がしやすかったんです。
加えてそのサービスが起動中はずっと必要なので、いちいちgetInstance(context)
するのが面倒だったのも理由です。。。
ただ、上記のようにしていたコードはNexus6 (Android 5.0.1)では問題なく動くものの、Nexus5 (Android 4.4.4)ではアプリが強制終了してLogcatには以下のようなログだけが出力。。。
Fatal signal 11 (SIGSEGV) at 0xd63794b7 (code=1), thread 6794 (ng.hogehoge)
***以下メモリダンプ***
とりあえず回避策
根本的な解決になっていないかもしれないですが、ReamインスタンスやRealmResultインスタンスの引き回しをやめました。
Realmが必要となるところでRealm.getInstance(context)
して、不要となったところでclose()
する、これだけです。
これで、クラッシュが発生していたNexus5 (Android 4.4.4)でもクラッシュは発生しなくなりました。
ただ、Realmでクエリーを投げた結果として得られるオブジェクトはいついかなる場合も、coreライブラリを通したメモリへの参照です。
Realmインスタンスがクローズされるともうアクセスすることはできません。
したがって、引き回しが必要なデータは別途Realmのモデルとは別のオブジェクトとして保持していく必要があります。
この辺りはデータの保持方法やロジック自体の再検討が必要になってきます。
自分の場合は、検索条件だけ保持しておいて、必要なときにまとめてクエリーを投げることにしました。
String mHoge;
String mHogeHoge
private HogeListener mHogeListener = new HogeListener() {
@Override
public void onUserHogeInput(String searchHoge) {
mHoge = searchHoge;
Realm realm = Realm.getInstance(this);
RealmResult<Hoge> result = getSearchedList(realm);
// データを保持する
ArrayList<String> hoogeNames = new ArrayList<>();
for (Hoge hoge : result) {
hogeNames.add(hoge.getName());
}
// もうRealmは不要なのでクローズ。メソッド内でRealmを完結させる。
realm.close;
// 保持したデータでいろいろ処理する
showHogeSearchResult(hogeNames);
}
};
private HogeHogeListener mHogeHogeListener = new HogeHogeListener() {
@Override
public void onUserHogeHogeInput(String searchHogeHoge) {
mHogeHoge = searchHogeHoge;
Realm realm = Realm.getInstance(this);
RealmResult<Hoge> result = getSearchedList(realm);
// 省略
realm.close;
}
};
private RealmResult<Hoge> getSearchedList(Realm realm) {
RealmQuery<Hoge> query = realm.where(Hoge.class);
if (mHoge != null && mHoge.equals("")) {
query.equalTo("hoge", mHoge);
}
if (mHogeHoge != null && mHogeHoge.equals("")) {
query.equalTo("hogehoge", mHogeHoge);
}
return query.findAll();
}
雑感
このような処理が必要となるケースは多くないとは思いますが、なんだかRealmの良さがスポイルされてしまっている気がします。
だれか、もっと良い解決方法があれば教えて下さい。。。