いさぽん部屋(isapon.com)

ゲーム系プログラマによる特に方針のないブログ。技術系とカレー、ラーメンネタ多めだったはずが、最近はダイエットネタ多め。

【Android】【Java】 アプリはたまに落としたほうが良い

f:id:no-operand:20150911221704p:plain

音ゲーなどリアルタイム処理のあるアプリで処理落ちが起こると悲惨なことに……遊ぶ人の解決方法としてはそろそろ処理落ちしそうになりそうだな……と思ったら一回アプリを終了させること。他に動いているアプリがあればタスクキルしても効果ありです。

Javaのメモリ管理は自動で行われる

Javaというプログラム言語とその仮想マシン(Javaの実行環境)の特徴として「メモリ管理が不要」というのがあります。プログラム中で使用されていないメモリを定期的に検索し、仮想マシンがメモリを回収します。

メモリ回収をガベージコレクションと呼ぶのですが、Javaにおけるガベージコレクションは「マーク&スイープ」という方法が取られます。

マーク&スイープとは何か

マーク&スイープはまず開始時にすべてのメモリにフラグを付けます(まだ調べてないよフラグ)。そして、プログラムでメモリをで参照している部分を探し出しひとつずつ使ってますよフラグを付けます。そして、すべてのプログラムを確認したところで、使ってますよフラグのないメモリを仮想マシンが回収するという仕組みです。

一見するととっても便利そう。いや実際便利なのですが、大きな問題を持っています。

マーク&スイープは一時的にプログラムを停止させる

チェックマークを付けている最中にプログラムからメモリを操作するとフラグ管理がうまくいかなくなることがあるため、マーク&スイープ実行時には一時的にプログラムを停止させます。最近ではマーク&スイープに「世代型」という方法をミックスし、マーク&スイープを少しづつ行うことで1回の停止時間を短くする仕組みが入っています(10秒かかるとしたら1秒を10回行うようにする感じです)。

主にガベージコレクションが動くのは「メモリが不足したとき」

メモリが不足すると不足分を補うためにガベージコレクションが全力で動きます。なにせメモリが足りないので、なるべく回収可能なものは全部回収しておきたいところですから。

結果起こることとして、

  1. メモリを確保しようとする
  2. メモリが不足する
  3. ガベージコレクションが行われる
  4. 処理落ちする
  5. 処理落ちしたデータを保管するためにメモリを確保する(1へ戻る)

というのがパターンとして比較的よくあります。そのため、Javaで組まれているプログラムは定期的にアプリを落とすか、プログラムで意識的にガベージコレクタを呼んであげないといけません。

プログラムで意図的にガベージコレクタを呼ぶとそれはそれで問題

System.gc(); これだけでガベージコレクタを呼び出せますが、これを行うと、その瞬間プログラムが一定時間止まります。どのくらい止まるかはその時々ですが、秒間60フレームで動いていたりすると結構致命的な時間で止まります。

また、CPUがフルパワーで動くのでスマホなんかだとバッテリーの消耗が激しくなります。

ガベージコレクタはメモリが不足した時以外に、システムが暇な時も動くのですが、ゲームなんかだとシステムが暇をしている時間も少ないですし、裏でこうしたアプリが動いているとシステムの負荷が高くなるのでどんどん悪循環に陥ります。

もっともよい解決方法

仕事で5~6年はJavaを使っていましたが、至った結論はJavaを使わない。これが一番確実な解決方法でした。

Javaは生産性が高いという話もありますが、生産性は技術でカバーできるはず。それよりも、ユーザーから見ればC++で作ろうがJavaで作ろうがほかの言語で作ろうが関係ありません。ユーザーにストレスを与えるような仕様のあるものはできれば使用を避けたい。

ガベージコレクションのアルゴリズムと実装

ガベージコレクションのアルゴリズムと実装

この本はかなりお勧め。出たときは「誰が買うんだよ!」と思いながら買ったのを覚えています。内容も濃く、高い技術力が身につく一冊ですが、買う人は限られているな~と思います。でもこの本に書かれている内容を理解できると、一目置かれるプログラマになれこと間違いなし!!

こういう本がもっと出るといいのになぁ。