Posted at
RealmDay 25

[iOS] Realm メモリ関連の例外対策

More than 3 years have passed since last update.

Realm Advent Calendar2015最後を担当させていただく@dekatotoroです:santa:

AWAという音楽ストリーミングサービスのiOSアプリをつくっています。

AWAでは、楽曲のメタデータからお気に入り情報、細かい設定情報など様々なデータをRealmに保存しています。Realm meetup #4でRealmを使ったアプリケーション設計の話もさせていただいたりして、2015年5月27日のリリースから約半年ほど運用してきました。

issue2269, issue2589あたりでも議論されたりしていますが、

今回はメモリ関連の例外に対してとっている対策をいくつか紹介します。

※ 2015/12/25日現在のStoreのversionではRealm-cocoa(0.96.2)を使用しています


Realmファイルの最適化

Realmのファイルサイズを確認すると思ったより大きくなっていることがあります。

ドキュメントの現バージョンにおける制限事項の「ファイルサイズと中間データについて」に記載がありますが、履歴データが残っていることが原因で肥大化していきます。Realmファイルが肥大化するとメモリー関連のクラッシュが増加する傾向があるため、できるだけ最適化する対策を行っています。

具体的には writeCopyToPath:error: を使ってアプリ起動時にRealmファイルのサイズを最適化を行っています。

起動が遅くなることを懸念して1日経っていたらなど条件を調整していましたが、ほとんどコストもかからないため現在は起動時に毎回実行しています。数十メガまで肥大化したファイルが数メガ程度になったりと履歴データが肥大化している場合はかなりの効果があります。

以前issue1243でも議論されていましたが、defaultで起動時のauto-compactはまだ組み込まれてないようです。


トランザクションの分割

トランザクションは分割するより一括で実行した方が高速ですが、大きなトランザクションを大量に実行するとメモリ枯渇の要因となります。大量のデータの書き込みの場合はトランザクションを分割して実行しています。閾値を決めて下記のように自動でcommitする関数を作ると便利です。

    AppRealm.commitAuto { (transaction: AppRealmTransaction) -> Void in

transaction.addArray([RLMObject]!)
}

    AppRealm.commitAuto { (transaction: AppRealmTransaction) -> Void in

for condition {
transaction.add(RLMObject)
}
}


Realmファイルの分割

Realmファイルの分割はCompactionとも関連しますが、Realmファイルが大きくなりすぎるとopen時にメモリ関連の例外が発生する可能性があります。端末やOSにより様々で一概に言えませんが、200Mを超えると発生頻度が増えてくるように思います。

Realmのデータが溜まっていくような設計の場合は、RLMRealmConfigurationでpathが指定できるので、データ設計上可能であれば分割することをおすすめします。FabricやGoogle AnalyticsなどでRealmファイルのサイズを送って分析してみると判断できると思います。


まとめ

クライアントでDBを使用するのは、Cacheや履歴などの用途が多いと思います。

Realmは非常に高速で扱いやすいですが、サーバのようにscaleできるわけではないので、データが増えてきた時にどうするか設計時に留意しておく必要があります。

また、クライアントではおろそかになりがちですがサーバの負荷試験のように相当数のデータを保存してテストしてみることも大事だと感じました。

年内には1.0にcoreもオープン化されるのかなーと思っていましたが、もう少し先になりそうですね。Realm の今後に期待しています :santa: