モノトーンの伝説日記

Apex Legends, Splatoon, Programming, and so on...

Xamarin.Android で lowmemorykiller が頻発する際の回避方法

 キーワード: クラッシュ (Crash), lowmemorykiller, Xamarin.Android, Large JSON File (> 10 MB)

 Xamarin.Android にて,大容量のデータを解析,Realm に保存する工程で,ほぼ毎回クラッシュ (Android のバージョンが低い方が頻発する傾向, 8.1 だと落ちなかったりすることも……) ことについてようやく原因を突き止めました。

 7/23 追記: object.AllocStringobject.AllocVector などの,ヒープ確保メソッドによるクラッシュも同様の方法で解決できます。Http 通信でヒープ不足に陥った場合,クラッシュする問題もこれで解決できます。

(余談) Android の ART/Dalvik VM 側の Heap Size 設定

 Xamarin.Android 環境は関係ないです。参考程度に。 こちらも増やさないと lowmemorykiller で落とされるようです

実機の Heap Size

 Android の Heap Size はデフォルトでは 16 MB24 MB です。私のエミュレーター環境では Java Heap は 24 MB (総メモリーは 1.5 GB; Android 5.0) でした。

 これはマニフェストによって増やすことができます。詳しくはこちらをご覧ください。

blog.ch3cooh.jp

エミュレーターの Heap Size

 エミュレーターは上のようなマニフェスト設定が反映されないため,エミュレーターの設定をいじる必要があります。

 例えば,マニフェストの largeHeap 設定値である 256 MB に設定します。

f:id:mntone:20180718221903p:plain

Mono の Heap Size

 Mono にも Heap Size が別にあります。上記の Java VM の Heap Size をいじる必要はありません。

 プロジェクトに env.conf のようなファイルを追加し,ビルド設定を AndroidEnvironment にします。

f:id:mntone:20180718222831p:plain

 このファイルに Mono GC のための設定を書きます。私の場合,次のようにしました。

MONO_GC_PARAMS=nursery-size=1m,soft-heap-limit=16m

 7/22追記, 7/29変更: この場合,1 MB で始まり,最大のヒープサイズが 16 M

 tarjannew より性能がいい GC みたいです。そのあたりゲームや大きなデータを扱うアプリは適切な設定を見つけるといい気がします。

 Mono GC の設定については,ガベージ コレクション - Xamarin | Microsoft Docs で。

 GC 自体の性能比較は https://blog.xamarin.com/xamarin-android-garbage-collection-improvements/ で。

まとめ

 数日間クラッシュ原因を探っていたのですが,どの設定がどういう風に絡まっているのか,Android Java 開発だと全く意識しないところをいじることになっているので調査が大変でした。Mono の GC の Heap Size は Mono GC 自体に渡すパラメーターによって決まっているというのを理解すればそこまで難しくない感。

 とりあえず例のアプリの Android 版の開発は順調に進みそうです。本当に良かった。内部コア Android のために書き換えるか? ってレベルまで行ったので……

 nursery-size 128 MB は割とデータ数が増えると到達しそうなので,もうちょっと上の 192 MB とかにした方がいいかもですね。3 時間ぐらい稼働させたら,100 MB まで行ってたので。と行ってもこれは合計 Heap Size だからもう少し余裕あるだろうけども。

mstdn.jp