
描画能力が大幅に向上、Flashに匹敵するアニメーションも可能に
膨大な数の仕様で構成されるHTML5は幅広い意味を持ち、一言で定義するのは難しいが、紀平氏はセッションの冒頭で「今回はスマートフォンの話に限定する(PCブラウザに関しては触れない)」と断ったうえで、次のように述べた。
「HTML5はHTMLとJavaScriptの複合体。それ自体はHTML4と大きく変わっているわけではない。もっとも重要な違いは、今までに比べてAPIが非常に豊富になったこと」
この豊富なAPIにより、HTML5では描画能力が大きく向上している。例えば、Canvasを使えばドット単位の描画が可能であり、ベクターグラフィックスを扱えるSVGによって曲線のある図形も描画できる。さらに、アニメーションもFlash並のクオリティが実現できるようになった。
ここで紀平氏は、同じ内容のアニメーションを2つの画面で同時に再生するデモを実施。一方はFlash、もう一方はHTML5で作成されたものだが、実際に会場のスクリーンで見ても見分けがつかなかった。しかし、HTML5は「残念ながらアプリ(ネイティブアプリケーション)に敵わないところもある」と紀平氏は続け、劣っている点として「3D」「音楽」「速度」の3つを挙げた。
まず3Dについては、スマートフォン標準搭載のブラウザでOpenGLが利用できないという制約がある。現時点でOpenGLをHTML5で使うための規格であるWebGLをサポートしているのは、Android用のFirefox for mobileのみだ(※注意)。音楽についても、音のタイミング調整が非常にシビアであるため「音ゲー」などに使うのは難しいという。ほかにも、画面タッチのタイミングでのみ音楽再生が可能(iPhone)、同時に2つの音源を鳴らせない(iPhone、WindowsPhone)など、制限が多い。そして、速度については、描画(レンダリング)の遅さ、JavaScript実行の遅さという、2つの問題を抱えている。
講演後の2月27日、Opera mobileもWebGLに対応しました。
続いて紀平氏は、描画手段の使い分けについて説明した。HTMLの描画手段としては、Canvas(ラスターグラフィックス)、SVG(ベクターグラフィックス)、CSS3(変形やアニメーション)の3つがあるが、このうちSVGはAndroid 2系でサポートされていないため、CanvasとCSS3の2つを取り上げた。ちなみに、SVGは工夫すればCanvasで代用可能だという。
「これまでの経験から、CanvasはAndroidで速度が問題になることはほとんどない。そのため、基本的にiPhoneでのfpsを上げることを考えて開発している。特に、iOS4ではdrawImageが遅いので、オンメモリのCanvasを利用してキャッシュに載せ、いかにdrawImageの回数を減らすかが重要」(紀平氏)
iOS5ではGPUのサポートが入ったことで、drawImageの重さが解消されてかなり速くなったが、別のAPIで重くなっているものもある。その回避のためには、やはりオンメモリのCanvasを利用するのが有効だ。
また、意外と見過ごされがちなこととして、紀平氏は「DOM構造でCanvasの上にさらにDOM要素を載せると重くなる。できるだけCanvasですべて処理して、DOM要素を上に載せないようにするべき」と指摘した。
紀平氏によると、Canvasは「じゃじゃ馬」のようなもので、特性を理解して使いこなせば優秀だが、それまでが大変なのだそうだ。一方、CSS3については「悪女」と表現した。そのココロは「とっつきやすいが、いきなり裏切る」というもの。
「CSS3はGPUサポートがあるので、最初はサクサク動作するが、同時に動く物体数が増えると急激に重くなる。そのため、デモでは快適に動いていたのが、ある日突然、使い物にならないほど重くなるようなことも起こりがち」(紀平氏)
また、CSS3は、特にAndroidでブラウザや端末間での互換性がないことが多い。変形の機能ではある程度の互換性が期待できるものの、アニメーションの機能についてはトラブルが散見されるという。こうした特性から、「シチュエーションに応じて変わるゲーム的なアニメーションや、同時に動くものが多いときはCanvas、1枚もののアニメーションで同時に動くものが少ないときはCSS3」(紀平氏)といった使い分けが効果的だ。

「王道」も「邪道」も使ってJavaScriptのメモリ消費を抑える
また、紀平氏は、JavaScriptの速度の問題についても説明。JavaScriptが重い理由としては、主にアルゴリズム、JIT(Just In Time)、GC(ガベージコレクション)の3つがあるという。
アルゴリズムが重いのは設計が悪いということなので、黙って設計を直すしかない。次に、本来は速くするための技術であるはずのJITが重いという場合、考えられるのはevalを使ったり、クロージャを生成していることだ。毎回JITのコンパイルを呼び出すようなコードを書いてしまうと、こうした問題が起こり得る。ただし、これはツールを使って容易に検出できるし、直すのもそう難しくはない。
「アルゴリズムやJITが重いという状況は、それほど問題にはならない。もっとも厄介で、JavaScriptが重くなる最大の原因は、GCにある」(紀平氏)
Androidでかなり複雑なJavaScriptを描いていると、よくGCが起こる。マイナーGCが起こっているうちはよいが、Full GCが走ってしまうことがあり、ひどい場合には2~3秒間止まってしまう。このような状況を防ぐための方法として、紀平氏は次のようにアドバイスした。
「V8は世代別GCのアルゴリズムを採用しているので、なるべく新世代にいるうちに、つまり使わないデータはとにかく早く参照を切ることが重要。マイナーGCが走っている段階で全部きれいにしてもらうのが鉄則で、それを守ることで、かなりGCを減らすことができる」
一方、iOSのMoile Safariの場合は、メモリが足らなくなると「突然落ちる」という特徴がある。これをいかに回避するか、メモリ消費をいかに抑えるかというのは、開発者にとって重要な問題だ。紀平氏は、この対策を「メモリとの戦い」と称して、「王道編」と「邪道編」に分けて解説した。
「“王道編”としては、やはり一般的によく知られている方法を確実に実行するしかない。大きく分けて2つあるが、まず1つ目は、何度も使うメモリをあらかじめ確保すること。例えば、頻繁に使う画像は最初に全部ロードしておく。2つ目は、上限の決まっているオブジェクトは初期化時に上限まで確保しておくこと。これによって、オブジェクト生成の回数を減らすことが重要」
また、メモリ消費を抑える対策の前提として、実機上でのメモリ使用量を確認し、自分のコードのどの部分がどれだけメモリを消費するかを把握したいところだが、これについて紀平氏は「メモリとの戦い:邪道編」で言及。
「“邪道編”の話については、自己責任でお願いしたい。まず、iPhoneシミュレータを使ってMac OS上でメモリ使用量を検証しようとしたが、信用できない結果となった。また、UIWideViewの中にJavaScriptを埋め込んでメモリ使用量を見ようとしたが、これも失敗した。UIWideViewの中で実行されるJavaScriptはJITのコンパイルが働かないので、やはりメモリ効率が全然違ってくる。そこで、褒められたやり方ではないが、一般に“Jailbreak”と呼ばれる方法をとり、ようやくメモリを確認することが可能となった」
Jailbreakしたうえでtopコマンドを走らせ、Mobile Saffariのメモリ使用量を常にモニタリングできるようになったそうだ。なお、紀平氏によれば、1回のJavaScriptでメモリ使用量が100MBを超えると「危険信号」であり、落ちるリスクが高まるという。
Jailbreakはオフィシャルのサポートが受けられない他、様々な重大なリスクを伴う非常に危険な行為であり、強く推奨されません。あくまで自己責任でお願いします。
さらに、紀平氏は実機でのプロファイルについても解説。自作のプロファイラでは、関数単位でcount、total、selfを取得するほか、どの関数のプロファイルを取得するか指定できるようにしており、CanvasなどのビルトインAPIも指定可能だという。
「プロファイルの結果は嘘をつかない。自分が重いと感じているところではなく、プロファイルが重いところを改善していくことが、速度の問題などを解消する近道」(紀平氏)
また、実機でのデバッグについては、console.logの重要性を強調。iPhoneではconsole.logを見られないと思っているユーザも多いが、デバッグログの設定項目を操作するだけでconsole.logを参照できることなどを指摘した。
終盤では、DeNAのゲームエンジン「ngCore」で開発したゲーム「忍者ロワイヤル」のHTML5バージョンを実際に動かすデモを披露。開発途上のバージョンながら、すでにネイティブアプリに近い速度でゲームを動かすことがHTML5でも可能となっていることをアピールし、紀平氏はセッションを締めくくった。
