2016年3月8日火曜日

アンドロイド:RAM が 2GB でも実際は…

最近、諸々の理由から スマホを2台更新しました。 今、話題の(悪い意味で)SHARP製「SH-02H」と、Google製(結局はLG製)「Nexus5X」の2台です。 今、あえてシャープにするなんて目の付けどころが悪いでしょ。 しかし、片手で持ちやすく、小型なのにフルHDです。 しかも液晶が120fps(秒速120コマ)で表示されるので、滑らかな動きがたまりません。 RAMは3GBもあります。 Xperia(Z5) のコンパクト機に性能で勝っているところがこんなにあります。 ちなみにネクサスのRAMは、2GBです。

今回はこのRAMがテーマとなります。 RAMとはマシンが扱えるデータ量ということなのでしょうか? このRAM以上の負荷をマシンにかけることはできません。 Android だと、同時に色々なアプリを開くし、インターネットやメールもすることでしょう。 一方でパソコンでも、Excel だ Word だと、いっぱい開く場合があります。 これは似ているんですけども、Android の場合は、パソコンのアプリケーションでいうところの右上「×」マークが無いんですよね。 Android4.x以降はタスクマネージメントの画面で、個別に起動中のアプリを葬ることができますが、 それでも、アプリたちの管理は原則的に"OS"に委ねられています。

Windows で、Excel だ Word だと、いっぱい開いている場合って、こまめにセーブしますよね。 だから、比較として何とも言えないんですけど、Andoroid の場合はゲームAとゲームBとゲームCとゲームDと4股していたら、 途中でネット…見た気がする。 途中で電話…かかってきたかもしれない。 途中でメール…したかもしれない。 いつの間にやらゲームAの途中データが消えていた。 こういうことがよくありますね。 これは、色々なアプリをユーザーがポコポコ開いていくうちにメモリを使いすぎて、マシンの負担が増えたことを意味します。 正確なアレはよく分かりませんが、RAMが2GBだったら、2GBに到達する前に(限界が近づいてきたら)OSが自動で実行中アプリのメモリを開放します。 メモリ解放とは、ファミコンで言うなら「リセットボタンを押す」に相当します。 この機能があるおかげで、アンドロイドさんは様々なアプリのインストールと同時並行的な使用に耐えることができるのです。

しかし、しかし。 タスクマネージメントを行う、Andoroid のOSは、もちろん常駐アプリです。 常駐アプリとは「常に駐屯している=常時起動している」アプリです。 メールとかセキュリティ系もそうでしょうね、いつ何時、情報が更新されるかわからないんだから、常時起きていて目を光らせておくしかない。 で、常駐アプリはメモリを消費します。 そして、哀しいことに、RAMが2GBあるのに実際に使えるフリー領域は半分以下の1GB弱しかない…。 ということはよくあります。 では、実際に最近買った2機種の情報を見てみましょう。 まだ、ほとんどアプリのインストールなどしていませんので、白紙状態に近いです。 アクオスフォンのSH-02Hだと、システムが1.0GB、常駐アプリが505MB、空きが1.2GBです。 最新のAndroid6.0を搭載したNexus5Xだと、空きが591MBです。 上記の値は使用状況によって変動します。しかし、まだほとんど手を付けていないので荒らされる前であることは確かです。

AndroidでOSはバージョンアップを繰り返していますが、 1.5 >>> 2.3 >>> 4.4 >>> 5.1 あたりが節目となるバージョンです。 Android2.2 の初期Galaxyを使っていたときは、2.3のゲームができずに悔しい思いをしたものです。 OSのバージョンアップは性能やセキュリティがアップするので、ユーザーにとって喜ばしいことなのですが、 しかし、新しいものほどメモリを食いますね。 Nexus5Xの、空きが600MB弱しかないのは、そういうことなのでしょう。

さきほど、RAMが2GBだったら、2GBに到達する前に(限界が近づいてきたら)OSが自動で実行中アプリのメモリを開放します。 と書きました。 これは、色々なアプリを開いて使っていくうちに、何回か前に開いたアプリの途中データが消えましたね。みたいな内容でしたが、 しかし、今使っているアプリの実行中に、まさに、2GB到達の危機が訪れたらどうなるのでしょうか? アプリは実行中に GC(ガーベッジコレクション)されるのですが、GCとはまあ不要な内部データをシュレッダーにかけるみたいな話です。 プログラムに問題があって、このGCがうまくできないとメモリがリークし続けます。 リークとはもれです。 コンクリートのひび割れに水が吸い込まれていくように、アプリからメモリがもれ続けます。 そんなこんなで、今使っているアプリの実行中に、まさに、2GB到達の危機が訪れたらどうなるか? Sowwww...「強制終了」となります。 これこそが、プログラマーが忌避する Out of Memory です。 よくユーザーレビューで「落ちる落ちるっていうけど、私は普通にプレイできましたよ。運営に文句言っているのは、最新機種に変えられない学生か何かじゃないの?」 的な煽りムンムンなお言葉を読むことができますが…。 そうなんです。Out of Memory とは環境に依存するバグなのです。 (ご使用になられているマシンの)空きメモリ次第なので、開発側も「ウソ、落ちたっていうヤツ多いな!オレのデバッグ機では普通に動いたけどな」と、首をかしげてしまいます。 勘違いしてはいけないのは、まったく同じ機種だとしても安心できないということ。A君の使い方だと落ちないし、B君の使い方だと落ちる。と、いうことがあり得ます。 この辺の事情はかなりカオスですね。混沌としております。

-------------------------------------
オレの作ったアプリ、10MBしかないから、リークしたって10MB付近でしょ?
 …そう思っていた時期がオレにもありました。 -------------------------------------

実際はアプリの容量というヤツは、そこまであてになりません。 私がメモリリークを考えずに作ったアプリなどは、10倍20倍が簡単にいっちゃいます。 では、実際に見ていきましょう。今回はタスクキラー系のアプリ「スマホ最適化」を利用させてもらっています。 使用端末は使い古したXperia Z1 SO-02F です。 とりあえず、容量の大きい四天王である4ゲームを立ち上げて、すぐに切ります。 世界線勇者110MB、ボクを殺すこと…83MB、奴は四天王…20MB、L.o.戦55MBとばらばらです。 では、トップ記録の世界線勇者を3分間プレイしてみます。 117MB、若干増えました。 ボクを殺すこと…も同様に約3分プレイ、第7ボスを倒せました。 結果として93MB、やはり若干増えました。 奴は四天王…も適当な時間をプレイ、29MB、同様の結果。ちなみにこれだけ Unity ではありません。 最後に、Legend of 戦士、これは95MBにアップ。55→95MBという大幅なメモリ増なのでメモリリークの傾向があるのかもしれません。 気になるので、もう少しプレイしてみましょう。 再開して3分くらいプレイして閉じて計測、今度は128MB、やばいですね、55→95→128MBとどんどんメモリ圧迫量が増えています。 これは連続してプレイしていると、どこかで強制終了となるかもしれません。

ちなみに、Xpreria Z1 SO-02F はもうシムカードを抜いてネット不接続状態だったのを忘れていました。 ネット接続があると、広告表示が発生するので、それ絡みでのメモリリークが発生するかも? です。 テザリングでネットを有効にして、世界線勇者を再開、約3分プレイすると…144MB、まあまあ増えましたね。 で、この時点で端末のメモリ使用量が結構増えてきました。 おろらくネット接続したことで、その他のアプリが雨後のタケノコの如く無数に発生した気配もあるんですが…(テキトー)。 ともあれ、546MB開放できます、と表示されています。 逆に言えば、それだけ使っているということです。 で、一覧の中から、ボクを殺すこと…、が消えました。 タスク管理画面ではまだ生きています。再開すると Unity のロゴが登場して最初から立ち上がる(オートセーブっぽいので前回の続きからですけど)。 これは、アプリがキラーされたことを示します。 このアプリキラーは賢いアンドロイドさんが自動的にやってくれます。 546MBともなると、だいたい80%くらいですか? メモリを使っているのでカツカツな感じです。

このXperia Z1の場合は、実際に使えるメモリが700MBくらいなんだと思います。 その中で、実用系やソーシャル系のアプリもメモリを要求しますから、実質「ゲーム枠」は300~400MBと考えていいでしょう。 もちろん、最新機種で3GB、4GBのマシンであればもっと余裕はあるのでしょうが、上は見たって仕方がない。 特に日本市場だけを見ると、世界平均よりもマシンの性能は上に位置しているハズ。 だから、2年前に入手した端末を基準にするくらいで調度いいのかもしれません。 いろいろな事情を加味すると、ハードにプレイしても100MBを越えないのが最低条件。 10分以下の標準的なプレイで、50MBを切るくらいが目標値となりましょう。

画像がどのくらい容量を使うのか? に関しては注意が必要です。 と、いうのも10KBの画像を100枚使っているから1MBくらいメモリを使ってんやろな、と思いがちですが、少し計算方法が違うようです。 例えば、同じ100x100ピクセルの絵であっても、容量が違いますよね。 私の場合、開発中の「アタックダンジョンMMF」でのモンスターグラフィックは150x100なんですが、3~8KBくらいでバラバラです。 余白が多い絵ほど、軽い傾向があります。 これが220パターンくらいあって、合計で1.2MBくらいになります。 し・か・し、実際に画像をJavaで(?)読み込む場合、同じ面積の画像は同じメモリを使います。 jpg や png などは圧縮をかけて、容量を減らしていますが、それを読み込んだ際には非圧縮です。 150x100x3(24bit=3byte)で計算すると、3~8KBの元画像が展開した結果は45KBとなります。 詳しいことはグーグルさんで各自調べてもらうとして、 想定外に大きくなる、と考えた方がよさそうです。

画像のキャッシュ機能を今作っていて、初回のみリソースから読み込んで画像データを取得して、 2回目以降はキャッシュデータを使って高速に読みこむというシステムです。 これで、キャッシュのサイズを取得すると、(まだ全ての画像をキャッシュ化できていないのに)7MB弱いっちゃってますからね。 まあ、背景とか、コマンドの元画像がデカイことが原因ですが…。 この感じでメモリーがGCされずに、もれ続けたらスゴいことになるのは容易に想像できます。 実際に私の経験上、ユーザーはもの凄く Out of Memory を連発します。 これに関しては「どうせクソみたいな低スペックマシンでやってんじゃないの?」と、なめていました。 あるいは、Galaxy というマシーンが悪いんじゃないのか? とか考えていましたが、世界的には、Samsung のシェアが Android 界隈では際立って高いですからね。 ただ単に割合の問題で Galaxy のバグが多かっただけです。 結局のところ、まともにプレイできた人ってどのくらいいるんだろう? って思ってしまいます。 この件に関しては、反省しております。直視しなければならない重大な問題だったのだよ、もっと前に。

今回は、ニューマシンも増えたので Android4.4 + 5.1 + 6.0 の3台(タブレットも含めれば4台)でデバッグができそうです。 特にネクサスはリファレンス機なので、これが基準ですよ。開発者必携のマシーンをついにゲットしたぞ。この意義は大きい。 しかし、その全てで問題なく動いても、それでも「胃の中の蛙」だと思わなければならないのでしょう。 世界中のユーザーに「安心してください、動きますよ」と保証する為には、使用メモリが少しだけ!…という裏付けが必要なのです。 この際、製作が長引いてもこの問題を解決することに注力したいものです。

0 件のコメント:

コメントを投稿