SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

ランタイムから迫るAndroidアプリのパフォーマンスチューニング ~ Dalvik/ART/NDKでの性能計測・比較・改善

チューニング前の測定結果

 チューニングを行う前に、基準となる実行速度を測定します。数値測定および比較を行うAndoid端末には「Nexus7(2013)」を使用しました。また、測定はAndoid端末のほか、比較のためPC(Corei5、3.4GHz)上でも行いました。測定結果はいずれも5回実行した平均をとっています。

 

基準となる実行速度の測定結果
実行環境 問数 正答数 処理時間(秒) 処理速度(問/分)
PC(Corei5 3.4GHz) 5,000 4,945 179 1,675.98
Dalvik(Nexus7 2013) 5,000 4,945 38,959 7.70
ART(Nexus7 2013) 5,000 4,945 24,169 12.41

 

 PC上ではスライドパズル全5,000問を処理するのに3分ほどしかかかりませんが、全く同じ処理をNexus7で実行すると、Dalvik上では10時間以上、ART上でも6時間以上もかかります。これを後ほどチューニングして、大幅にパフォーマンスを改善させます。

 

Dalvik/ARTのヒープ領域管理

 チューニングを行う前にもう1つ、DalvikおよびARTのヒープ領域管理の方式を理解しておきましょう。

 

コンカレントGCを採用

 Dalvik/ARTでは、ヒープ領域の管理をランタイム側が担当し、不要になった領域の解放を「GC」(garbage collection)が実行する仕組みになっています。この仕組みにより、開発者はオブジェクトの解放を考える必要がなく、領域の解放し忘れによるメモリリークも未然に防がれます。一方で、GCは不要なオブジェクトを探してから解放するため、スループットは、開発者が明示的に最適な解放処理を行う場合よりも下がります。

 GCにはいくつか方式がありますが、Dalvikでは「コンカレントGC」が採用されています。コンカレントGCは、スレッドの停止を最小限に抑えて可能な限りバックグラウンドで処理を行うため、アプリの応答性や(CPUの余剰コアがある場合には)スループットの改善などが見込めます。

 

DalvikのGCが抱える問題とARTでの改善

 しかし、DalvikでコンカレントGCが有効に稼働するのは、ヒープの利用が少なめでアイドルタイムが十分にあるアプリの場合です。そうでないアプリの場合、コンカレントGCの実行完了を待つWAIT_FOR_CONCURRENT_GCが多発したり、GC_FOR_MALLOCという並列動作を行わない単純なマーク&スイープ方式のGCの実行が多くなったりします。GC_FOR_MALLOCは、オブジェクト生成時にヒープ領域に空きが不足すると起動されます。そして、当該スレッド(オブジェクトを生成しようとしたスレッド)がそのままGC処理を担当するため、アプリのパフォーマンスに直接影響が出ます。

 短命オブジェクトの解放で効果を発揮する「世代別GC」が採用されていないことも、注意点として挙げられます。Dalvikでは、GCが発生するたびにヒープの全領域を探索することになるため、生存オブジェクトの数が極端に多かったり、オブジェクトの生成と解放を繰り返したりするとパフォーマンスが劣化します。

 一方で、ARTはGCが大幅に改良されています。Dalvikと違い、コンカレントGCが有効に動作するケースが多く、実際にスライドパズルアプリで測定したところ、99%以上のGCはコンカレント動作をしました。さらには、新たに生成されたオブジェクトのみを対象とした高速なGCも導入され、世代別GCの利点を一部得られるようになりました。

 

フラグメンテーション(断片化)の解消

 また、ヒープ領域管理でもう1つ欠かせないのが「フラグメンテーション(断片化)の解消」です。フラグメンテーションとは、長期間稼働中のアプリでヒープ領域の確保と解放を繰り返す間に、細かい領域が飛び飛びに確保された状態になることです。フラグメンテーションが発生している状態で巨大な(連続した)領域の確保をしようとすると、ヒープに空き容量が十分にあってもGCが発生します。これが繰り返されるとGCが頻発してパフォーマンスに影響し、最終的にはOutOfMemoryErrorが発生します。

 通常はフラグメンテーションを解消するために、GCとともにCompactionという処理が行われますが、DalvikのGCにはCompactionが実装されていません。そのため、長時間起動するアプリはある程度考えて領域の確保と解放をしないとフラグメンテーションが発生し、徐々にパフォーマンスが劣化していきます。

 これはARTでも同様で、原稿執筆時点ではCompactionを行いません。しかし、Lollipop以降のARTのソースコードにはCompactionを行うGCが追加されているため、そう遠くないうちに利用可能になりそうです。

次のページ
チューニング①「オブジェクトプールの導入」

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

羽山 純(ハヤマ ジュン)

株式会社ラクーン 技術戦略部 テクニカルディレクター。開発からインフラまでシステム全般を担当。株式会社ラクーン技術ブログも運営してます。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/8333 2014/12/16 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー