Android上のアプリケーションはJava言語で開発できるが、PCやサーバー向けのJava仮想マシンとは異なる「Dalvik仮想マシン」上で動作する。Dalvik仮想マシンは、モバイル向けに特化されているのが特徴である。

 Androidアプリケーションの開発では、Javaの開発現場で培ってきた資産やノウハウを生かすことができる。だが、基本的にPC上で動作させるJavaアプリケーションと同様に考えてしまうと、思わぬ落とし穴に陥ることになる。

 そこで、主にメモリー管理の面からJava仮想マシンとDalvik仮想マシンの違いを見ていくことにする。

 両者とも、メモリー管理はガベージコレクタ(GC)が担当する。ヒープ領域に空きがない場合、不必要なオブジェクトを回収して空き領域を作るのがGCの役割である。Java仮想マシンでは「世代別GC」という方式を採用しているが、Dalvik仮想マシンは「マークアンドスイープ」という方式を採用している。

 世代別GCでは、ヒープを大きく「New世代領域」と「Old世代領域」の二つに分ける。New世代領域では、生成直後のオブジェクトが順次保存され、生成後、回収されずに生き残った長命のオブジェクトはOld世代領域にコピーしていく。

 この方式は、「大多数のオブジェクトは短命」という仮説に基づいたものであり、大量の短命なオブジェクトを回収するのに最適化されている。ヒープを世代という概念で分割したことにより、一度にすべての世代を再配置する必要がない。結果として、パフォーマンスに影響を与えるGCの起動を最小限にとどめることができる。

 これに対しDalvik仮想マシンでは、まず確実に必要なオブジェクトに印を付け、そのオブジェクトから参照をたどり、使っているオブジェクトに印を付けていく。この作業を繰り返して、印の付いていないオブジェクトは不必要なオブジェクトとみなし、破棄する。

 Androidはマークアンドスイープ方式のGCを実行中、すべてのスレッドを停止する。その間、動作がもたつくような感覚を、ユーザーに与えてしまうことになる。

 Java仮想マシンのGCは短命なオブジェクトの回収に最適化されているが、AndroidのGCはそのような処理には適していない。Androidでは、なるべく短命なオブジェクトの作成は避けるべきである。

画面1●DDMS
[画像のクリックで拡大表示]

 Android SDKには「DDMS(Dalvik Debug Monitor Service)」(画面1)と呼ばれるデバッグ用のツール群が付属しており、そのツールの一つ「Allocation Tracker」では、メモリーの確保状況を追跡できる。どのスレッドのどのタイミングでメモリーが割り当てられたのかが一目瞭然なので、活用するといいだろう。

 Javaの「常識」は、必ずしも通用するとは限らない。

渡島 健太(わたしま けんた)
アシアル株式会社 エンジニア
1987年福岡生まれ。Perlで書かれたCGIスクリプトの改造がきっかけで初めてプログラミングに触れる。2009年にアシアル株式会社に入社。以後、同社が近年積極的に展開するスマートフォン事業に従事し、Android向けアプリ開発のほか、iPhone向けサイトのデザインなども手がける。