キーワード: クラッシュ (Crash)
, lowmemorykiller
, Xamarin.Android
, Large JSON File
(> 10 MB)
Xamarin.Android にて,大容量のデータを解析,Realm に保存する工程で,ほぼ毎回クラッシュ (Android のバージョンが低い方が頻発する傾向, 8.1 だと落ちなかったりすることも……) ことについてようやく原因を突き止めました。
7/23 追記: object.AllocString
や object.AllocVector
などの,ヒープ確保メソッドによるクラッシュも同様の方法で解決できます。Http 通信でヒープ不足に陥った場合,クラッシュする問題もこれで解決できます。
(余談) Android の ART/Dalvik VM 側の Heap Size 設定
※ Xamarin.Android 環境は関係ないです。参考程度に。 こちらも増やさないと lowmemorykiller で落とされるようです
実機の Heap Size
Android の Heap Size はデフォルトでは 16 MB
か 24 MB
です。私のエミュレーター環境では Java Heap は 24 MB (総メモリーは 1.5 GB; Android 5.0) でした。
これはマニフェストによって増やすことができます。詳しくはこちらをご覧ください。
エミュレーターの Heap Size
エミュレーターは上のようなマニフェスト設定が反映されないため,エミュレーターの設定をいじる必要があります。
例えば,マニフェストの largeHeap
設定値である 256 MB
に設定します。
Mono の Heap Size
Mono にも Heap Size が別にあります。上記の Java VM の Heap Size をいじる必要はありません。
プロジェクトに env.conf
のようなファイルを追加し,ビルド設定を AndroidEnvironment
にします。
このファイルに Mono GC のための設定を書きます。私の場合,次のようにしました。
MONO_GC_PARAMS=nursery-size=1m,soft-heap-limit=16m
7/22追記, 7/29変更: この場合,1 MB で始まり,最大のヒープサイズが 16 M
tarjan
は new
より性能がいい 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 だからもう少し余裕あるだろうけども。