Androidアプリを性能のために設計する最高の方法

2011/8/24 22914hit

Designing for Performanceを和訳してみました。
スマートフォンは従来のケータイに比べて高性能ですが、PCやサーバと比べると限られたリソースしか無いです。
特に重要な違いとして、ノートPCなどと比べてもバッテリーを使用しないことを要求されます。
AndroidはJavaをサポートしているので、スマートフォンの中でも既存の開発知識を使いやすいです。
しかし、一部において、パフォーマンスを改善するために、Javaではよくない とされる手法を使う場合もあり得ます。
この章ではそういう知識が具体例を交えて紹介されていました。

原文

性能のために設計する最高の方法

Androidアプリケーションは限られたパワー、限られた記憶容量、限られたバッテリーを持つモバイルデバイスで実行されます。
そのため、効率的に動く必要があります。
たとえ十分に速かったとしても、バッテリーライフはアプリを最適化する理由となります。
バッテリーライフはユーザーに取って重要です。
そしてAndroidはバッテリーを使用して、バッテリーが消費する原因があなたのアプリケーションにあるかをユーザーに知らせます。
ノート
このドキュメントは主にマイクロ最適化についてカバーするが、これがあなたのアプリケーションの成否を握るとは限らない点に注意してください。
正しいアルゴリズムとデータ構造を選択することは常に優先されるべきことですがこのドキュメントの範囲外です。

はじめに

効率的なコードのために2つの基本的なルールがあります。
・必要ないことはするな
・可能ならばメモリーを割り当てるな

注意深く最適化する

このドキュメントはAndroid特有のマイクロ最適化について記載しています。
そのため、あなたは既にどのコードが最適化されるべきか正確に理解できるプロファイリングを使用し、変更した結果の影響を図る方法があると仮定します。
あなたには費やすべきそれだけの技術的な時間しかないので、懸命にそれを費やしている事を知ることは重要です。
(プロファイリングと効果的なベンチマークについてはおわりにを読んでください)
このドキュメントはあなたがデータ構造とアルゴリズムについて最高の決定し、APIの将来的な問題ついても考慮したと仮定します。
もし、そのようなアドバイスを必要とするのであれば、Josh BlochのEffective Java 項目47を見てください。

Androidアプリをマイクロ最適化することは、アプリが複数のハードウェアプラットフォームで動作す場合慎重を要する問題の一つです。
VMが異なるバージョン、、異なるプロセッサ、異なる速度、あなたは単にデバイスXの要因FはデバイスYより早いまたは遅いということが出来るだけで、1台の装置の結果が他のデバイスで一致するとは限りません。

特にエミュレータの測定は他の殆どの装置の結果と連動しません。
JITを使う場合とそうでない場合もです。
JITのための最適なコードが必ずしもJIT以外で最適なコードではありません。
あなたのアプリがどのデバイスで動くか知っているのであれば、そのデバイスでテストする必要があります。

不要なオブジェクトの生成を避ける

オブジェクトの生成は無償ではありません。
一時オブジェクトのためにスレッドの割り当てをプールする世代のガベージコレクションはより低負荷ですが。しかし、メモリーを割り当てることはメモリーを割り当てないより常に高負荷です。
Gingerbreadの並列コレクターはこれを助けます。しかし、不要な仕事は常に避けるべきです。

このように、不要なインスタンスの生成は避けるべきです。
この事例のいくつかのヘルプ:
  • もし、Stringを返すメソッドを持っており、その戻り値を常にStringBufferにより追加される事を知っているのであれば、一時的なオブジェクトを作る代わりに直接appendを呼ぶようにシグネチャと実装を変えてください。

  • 入力データからStringを得るときはコピーを作成する代わりに最初のデータのSubstringを返そうとしてください。
    新しいString オブジェクトを作りますがそれはchar[]とデータを共有します。
(トレードオフ、あなたが至る所でそれをメモリーにいれ、入力された最初の小さな部分を使っているだけならば)

やや過激なアイデアは多次元配列を複数の1次元配列にわけます。
Integerの配列よりintの配列がいいです。これは(int,int)の多次元配列より2つのint配列のほうがより効率的であるという一般論を意味します。
その他プリミティブな型においても同様です。
もし、(Foo,Bar)オブジェクトの配列を実装しようとしているならば、2つのFoo[] Bar[]配列が普通はより効率的になることを思い出してください。

一般的に、可能なかぎり短期的な一時オブジェクトを作ることを避けてください。
作られるオブジェクトの数が減れば、ガベージコレクションの頻度は少なくなり、それはユーザーの操作性に直接的なインパクトを与えます。

パフォーマンス神話

以前のバージョンでこのドキュメントでは紛らわしい事を書いていました。
ここでそれを整理します。
JITが無いデバイスではインターフェイスより具体的なオブジェクト型の変数からメソッドを呼び出したほうがわずかに効率的なのは事実です。
例えば両方のケースでMapがHashMapだとするとHashMap型の変数でメソッドを呼び出すほうがMap型の変数より速いです。
これは2倍遅くなるといった話ではありません。
実際のところは6%程度の違いです。しかも、JITはそれら二つの差を効果的になくします。

JITの無いデバイスでは、キャッシュフィールドによるアクセスは繰り返しフィールドにアクセスするより約20%速くなります。
JITでは、フィールドにアクセスするコストはローカルにアクセスするコストとほぼ同じです。
そのためコードが読みやすくなるのでないならば、価値がある最適化とは言えません。
これはfinal,staticそしてstatic finalフィールドに対しても当てはまります。

Staticを好む

もしオブジェクトフィールドにアクセスする必要が無いのであればメソッドをstaticにしてください。
そのおまじないにより15〜20%はやくなります。
それはいい方法でもあります。
なぜなら、メソッドがオブジェクトの状態を変えることがないとメソッドのシグネチャで宣言できるからです。

内部のgetter,setterを避ける。

C++のようなネイティブ言語では、(i=mCountのように)直接フィールドにアクセスする代わりに(i = getCount()のような)getterを使うことはよくあります。
これはC++のための優れた習慣です。
なぜなら、コンパイラが直接インラインでアクセスすることが出来て、あなたが必要となれば、いつでもアクセスを制限したりデバッグしたりしたコードを加えることができるからです。

これはAndoridではいいアイデアと言えません。
JITが無いとき、直接フィールドにアクセスするのはgetterより約3倍速いです。
JITがあると、(直接フィールドにアクセスするのがローカルアクセス並みに早くなったので)直接フィールドにアクセスするのはgetterより約7倍速いです。
これはFroyoについて真実です。しかし、将来JITがインラインでgetterメソッドを実行するとき改善されます。

定数のためにStatic Finalを使用する。

クラスの上位にある以下の宣言について考えてみます。

static int intVal = 42;
static String strVal = "Hello, world!";

コンパイラはclinitをコールする初期化メソッドを作成し、クラスが最初に使用されるときに呼び出されます。
メソッドはintValに42を登録し、クラスファイルのStringコンスタントテーブルよりstrValのための参照を引き出します。

finalでこの面倒を改善することが出来ます。

static final int intVal = 42;
static final String strVal = "Hello, world!";

クラスはclinitをもはや必要としません。
intValは直接42を使用し、strValへのアクセスはフィールド参照より安価な文字列定数を使用します。
ノート
この最適化は任意の参照型には当てはまらずプライマリタイプとString定数にだけ当てはまる事に注意してください。
しかし、可能なかぎり定数をstatic finalとするのは良い手法です。

強化されたfor loop文法を使用する。

強化されたループ(for eachとも言われる)はiterableなインターフェイスを実装するコレクションと配列のために使用できます。
iteratorインターフェイスによってコレクションにhasNext()とnext()が割り当てられます。
手書きでカウントされるArrayListのループは約3倍速いです。(JITの有無に関わらず)
しかし他のコレクションに対してのループ構文は正確にiteratorを使用した場合と等しいです。
配列を繰り返す案がいくつかあります。

static class Foo {
int mSplat;
}
Foo[] mArray = ...

public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}

public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;

for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}

public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}

zero()は最も遅いです。
なぜなら、JITが配列長を取得するためのコストを最適化することがまだ出来ないためです。

one()はそれより速いです。
ローカル変数を参照しルックアップを避けます。
array lengthだけはパフォーマンスを提供します。

two()はJITの無い端末では最速で、JITがある端末ではone()と同等です。
Java1.5で採用された強化されるループ構文を使用します。

以下をまとめます。
通常強化されたループを使用してください。
しかし、パフォーマンスが重要なArrayListの繰り返しのために手書きで数えられるループを考慮してください。
Effective Java項目46 を見てください。

PrivateインナークラスとPrivateアクセスの代わりにパッケージを考慮してください

以下のクラス定義を考えてみてください。

public class Foo {
private class Inner {
void stuff() {
Foo.this.doStuff(Foo.this.mValue);
}
}

private int mValue;

public void run() {
Inner in = new Inner();
mValue = 27;
in.stuff();
}

private void doStuff(int value) {
System.out.println("Value is " + value);
}
}

ここで注意すべきのは、private inner classとして定めた内部クラス(Foo$Inner)が外のプライベートメソッドとインスタンスフィールドに直接アクセスしているということです。
これは正しくコードは「Value is 27」を出力します。
問題はJava言語として適切であったとしても、VMがFooとFoo$Innerが別のクラスなので、直接のアクセスは許可されていないと考える事です。
このギャップを埋めるために、コンパイラは2つのメソッドを生み出します。

/*package*/ static int Foo.access$100(Foo foo) {
return foo.mValue;
}
/*package*/ static void Foo.access$200(Foo foo, int value) {
foo.doStuff(value);
}

インナークラスがアウタークラスのmValueフィールドかdoStuffメソッドを呼び出す必要があるときはこれらのstaticメソッドを使用します。
これが意味することはメンバーフィールドにアクセッサーメソッドでアクセスするコードが現実になるということです。
既に直接的なアクセスよりアクセッサがどれだけ遅いか説明しているように、これはパフォーマンスに影響する言語特有の見えないイデオムの例です。

もし、高性能を必要とする地点で使用するなら、内部クラスから呼ばれるフィールドとメソッドをプライベートからパッケージに変更することでオーバーヘッドを回避できます。
残念ながら、この方法は同じパッケージの別のクラスから直接フィールドを操作できることを意味するため、広く公開するAPIでは使用すべきではありません。

浮動小数点を注意深く使う。

経験上、浮動小数点はAndroidのデバイスで2倍程度遅いです。
これはFPUとJITがないG1とFPUとJITがあるNexus Oneで事実です。
もちろん、2台の端末には10倍の絶対的な速度差があります。

最新のハードウェアにおいてdoubleとfloatにこの性能差はありません。
サイズはdoubleが2倍広く、デスクトップと同様にサイズが問題でなければ、floatよりdoubleを好む必要があります。

また、Integerでさえ、いくつかのチップでは複数のハードウェアを持つが、ハードウェアでの分割機能を欠如しています。
そのような場合、整数の分割と係数はソフトウェアで処理されます。

いくつか考えるべきは、ハッシュテーブルを設計している時や、沢山の数学を行う必要がある時です。

ライブラリを知り、使う

あなたの処理を実行するよりライブラリコードを好む理由があります。
通常の理由に加えて、システムは自由に手作業で作られたアセンブラコード(JITがJavaで作成できる最高のコードより良い場合がある)を呼べることを覚えておいてください。
典型的な例はString.indexOfとその仲間です。これはDlavicで代わりにインラインされています。
同様にSystem.arraycopyメソッドは手作業で作るコードよりNexus oneにおいて9倍速いです。
Effective java 項目47を読んでください。

ネイティブコードを注意深く使う

ネイティブコードが必ずしもJavaより効率的であるとは限りません。
一つはJavaとネイティブコードを移行するコストがあります。加えて、JITはそれらをまたがって最適化出来ません。
もし、ネイティブリソース(ネイティブヒープ上のメモリ、ファイル記載子など)を割り当てると、これらのリソースのタイムリーなコレクションを取得するのはかなり難しくなります。
あなた自身もまたアーキテクチャごとにコンパイルを行う必要があります。
同じアーキテクチャに見えるものに対してさえ複数のバージョンに対してコンパイルする必要があるかもしれません。
G1のARMプロセッサ向けにコンパイルされたネイティブコードはNexus OneのARMプロセッサで最大の性能を活かすことが出来ません。そしてNexus OneのARMプロセッサ向けにコンパイルされたネイティブコードはG1のARMプロセッサで動きません。

ネイティブコードはJavaアプリの速度をあげることより、Android向けの既存コードベースを持つときに主に役立ちます。
ネイティブコードを使う必要があるなら、JNIチップスを読む必要があります。
(Effective Java項目54を読んでください)

おわりに

最後に、常に測定してください。
最適化を行う前に問題があることを確認して下さい。
現在のパフォーマンスを正しく測定出来ることを確認してください。
さもなければ、試した結果を測ることが出来ません。

このドキュメントによるあらゆる主張はベンチマークによって裏付けされます。
ベンチマークのためのソースはcode.google.com "dalvik" project.に有ります。
ベンチマークはJavaのマイクロベンチマークによってビルドされています。
マイクロベンチマークは正しく測るのが難しいので、カリパスはあなたのために困難な作業をし、あなたが測っていないケースさえ見つける努力をします(なぜならVMあなたのコードを最適化することが出来るので)
マイクロベンチマークを走らせるためにカリパスを使うことを我々は強く推奨します。

Traceviewも役立つと思うかもしれません。
しかし、それが今のところJITを無効化してしまうことを知っておく必要があります。
そしてJITが戻ってくるときにコード特有の問題を起こすことがあります。
それはTraceviewデータで動かしたあとにTraceview無しで動くとき、結果として生じるコードが実際に早くなるようにTraceviewデータを使うときに特に重要です。

Except as noted, this content is licensed under Apache 2.0.

前:アプリをAndroid 3.0へ最適化する最高の方法 次:フラグメント

関連キーワード

[Android][Java][モバイル][IT][翻訳]

コメント

名前:ひさねこ|投稿日:2011/10/07 17:53

今日はこのサイトと原文を読みながら Android の性能について勉強しました。 気が付いた点を以下に分けて列挙します。

---------------------
※1. Battery life: バッテリー寿命
※2. 「Androidはバッテリーを使用して」のあたりの日本語が怪しいです。

英語: Battery life is important to users, and Android's battery usage breakdown means users will know if your app is responsible draining their battery.

バッテリーライフはユーザーに取って重要です。そしてAndroidはバッテリーを使用して、バッテリーが消費する原因があなたのアプリケーションにあるかをユーザーに知らせます。

バッテリー寿命はユーザーにとって重要で、Android の使用に伴うバッテリーの消耗は、そのアプリケーションがバッテリー消耗の原因になっているかどうかをユーザーに知らせることを意味します。
---------------------
※ performance と decision が翻訳されていません。

英語: the future performance consequences of your API decisions

APIの将来的な問題

API 決定に伴う将来的なパフォーマンスの影響
---------------------

名前:ひさねこ|投稿日:2011/10/07 17:54

※ 翻訳されていません。

英語: Using the right data structures and algorithms will make more difference than any of the advice here, and considering the performance consequences of your API decisions will make it easier to switch to better implementations later (this is more important for library code than for application code).

  *** 翻訳なし ***

正しいデータ構造とアルゴリズムを使用することはここにあるどのアドバイスよりも大きな変化をもたらすことでしょう。API 決定に伴う将来的なパフォーマンスの影響を考慮することは後ほどより優れた実装に置き換えることを簡単に行えるでしょう(これはアプリケーションコードよりもライブラリコードにとってより重要です)。
---------------------
※ "One of the ・・・ an Android app" が主語。

英語: One of the trickiest problems you'll face when micro-optimizing an Android app is that your app is pretty much guaranteed to be running on multiple hardware platforms.

Androidアプリをマイクロ最適化することは、アプリが複数のハードウェアプラットフォームで動作す場合慎重を要する問題の一つです。

Android アプリをマイクロ最適化する際に直面するもっとも厄介な問題の一つは、アプリが複数のハードウェアプラットフォーム上で動作することを十分に保証する必要があるということです。
---------------------

名前:ひさねこ|投稿日:2011/10/07 17:55

※1. "Different versions ・・・ speeds." の部分が正しく翻訳されていません。
※2. 後半部分も問題ありそうな気がします。

英語: Different versions of the VM running on different processors running at different speeds. It's not even generally the case that you can simply say "device X is a factor F faster/slower than device Y", and scale your results from one device to others.

VMが異なるバージョン、、異なるプロセッサ、異なる速度、あなたは単にデバイスXの要因FはデバイスYより早いまたは遅いということが出来るだけで、1台の装置の結果が他のデバイスで一致するとは限りません。

様々なスピードで動作する様々なプロセッサで動作する様々なバージョンの VM が存在します。一般に「デバイス X はデバイス Y よりも F 因子だけ速い/遅い」と単純に言えたり、あるデバイスの結果を他のデバイスにも横展開できるケースはほとんどありません。
---------------------
※1. Generational GC: 世代別ガベージコレクション
※2. ここでは負荷の問題ではなく、コストの問題について言及しています。
※3. "A generational GC with ・・・ objects" の翻訳も問題がありそうです。

英語: A generational GC with per-thread allocation pools for temporary objects can make allocation cheaper, but allocating memory is always more expensive than not allocating memory.

一時オブジェクトのためにスレッドの割り当てをプールする世代のガベージコレクションはより低負荷ですが。しかし、メモリーを割り当てることはメモリーを割り当てないより常に高負荷です。

一時オブ

名前:ひさねこ|投稿日:2011/10/07 17:56

---------------------
※1. Generational GC: 世代別ガベージコレクション
※2. ここでは負荷の問題ではなく、コストの問題について言及しています。
※3. "A generational GC with ・・・ objects" の翻訳も問題がありそうです。

英語: A generational GC with per-thread allocation pools for temporary objects can make allocation cheaper, but allocating memory is always more expensive than not allocating memory.

一時オブジェクトのためにスレッドの割り当てをプールする世代のガベージコレクションはより低負荷ですが。しかし、メモリーを割り当てることはメモリーを割り当てないより常に高負荷です。

一時オブジェクト用にスレッド単位でアロケーションプールを持つ世代別ガベージコレクションではアロケーションのコストは安いものですが、メモリーを割り当てることは常にメモリーを割り当てない場合よりもコストは高くつくものです。
---------------------
※ 翻訳されていません。

英語: If you allocate objects in a user interface loop, you will force a periodic garbage collection, creating little "hiccups" in the user experience.

  *** 翻訳なし ***

ユーザーインターフェースのループでオブジェクトをアロケートすれば、定期的なガベージコレクションが強制的に行われ、ユーザーエクスペリエンス上のちょっとした問題を引き起こすことになるでしょう。
---------------------

名前:ひさねこ|投稿日:2011/10/07 17:57

※ thus: だから、従って。

英語: Thus, you should avoid creating object instances you don't need to.

このように、不要なインスタンスの生成は避けるべきです。

従って、不要なオブジェクトのインスタンスの生成は避けるべきです。
---------------------
※1. string: 文字列(小文字の s なので)。
※2. 「直接appendを呼ぶように」とは英文に書かれていません。

英語: If you have a method returning a string, and you know that its result will always be appended to a StringBuffer anyway, change your signature and implementation so that the function does the append directly, instead of creating a short-lived temporary object.

もし、Stringを返すメソッドを持っており、その戻り値を常にStringBufferにより追加される事を知っているのであれば、一時的なオブジェクトを作る代わりに直接appendを呼ぶようにシグネチャと実装を変えてください。

文字列を返すメソッドがあり、戻り値が常に StringBuffer に追加されることが分かっているなら、一時的なオブジェクトを生成するのではなく、直接(StringBuffer への)追加を行うようにシグネチャと実装を変更してください。
---------------------

名前:ひさねこ|投稿日:2011/10/07 17:58

※1. extract: 取り出す。
※2. 「最初のデータの・・・」という表現は日本語だけだと理解しにくいかもしれません。

英語: When extracting strings from a set of input data, try to return a substring of the original data, instead of creating a copy.

入力データからStringを得るときはコピーを作成する代わりに最初のデータのSubstringを返そうとしてください。

入力データから文字列を取り出す場合は、コピーを作成するのではなく、もとの入力データの部分文字列を返すようにしてください。
---------------------
※ 日本語が理解しがたいものになっています。

英語: The trade-off being that if you're only using a small part of the original input, you'll be keeping it all around in memory anyway if you go this route.

トレードオフ、あなたが至る所でそれをメモリーにいれ、入力された最初の小さな部分を使っているだけならば

もとの入力のほんの少ししか使用していない場合は、このルートを通ればそれ(=もとの入力データすべて)をずっとメモリに保持することになり、これはトレードオフになります。
---------------------

名前:ひさねこ|投稿日:2011/10/07 17:59

※1. 英文には多次元配列と書かれていません。
※2. (int,int) objects の "objects" が翻訳されていません。

英語: this also generalizes to the fact that two parallel arrays of ints are also a lot more efficient than an array of (int,int) objects

これは(int,int)の多次元配列より2つのint配列のほうがより効率的であるという一般論を意味します

これは一般化すると、 (int,int) オブジェクトの配列よりも int の配列を二つ並列させる方がずっと効率的であるということになります。
---------------------
※ 英文には「(Foo,Bar)オブジェクトの配列を実装しよう」とは記述されていません。「(Foo,Bar)オブジェクトを保存するコンテナを実装・・・」とあります。

英語: If you need to implement a container that stores tuples of (Foo,Bar) objects, try to remember that two parallel Foo[] and Bar[] arrays are generally much better than a single array of custom (Foo,Bar) objects.

もし、(Foo,Bar)オブジェクトの配列を実装しようとしているならば、2つのFoo[] Bar[]配列が普通はより効率的になることを思い出してください。

(Foo, Bar) タプルのオブジェクトを保存するコンテナを実装する必要がある場合は、 Foo[] 配列と Bar[] 配列を二つ並列させる方が (Foo, Bar) オブジェクトの一つの配列にするよりもずっと効率的であることを思い出すようにしてください。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:01

※ 翻訳されていません。

英語: (The exception to this, of course, is when you're designing an API for other code to access; in those cases, it's usually better to trade good API design for a small hit in speed. But in your own internal code, you should try and be as efficient as possible.)

  *** 翻訳なし ***

(勿論、例外もあります。他のコードがアクセスする API を設計している場合は、普通、スピードを少し上げることよりも良い API 設計を行うことを優先するのが良いでしょう。しかし、自分だけの内部コードでは、できるだけ効率的にするように心がけるべきです。)
---------------------
※ 過去形であることに注意する必要があります。

英語: So, for example, it was cheaper to invoke methods on a HashMap map than a Map map, even though in both cases the map was a HashMap.

例えば両方のケースでMapがHashMapだとするとHashMap型の変数でメソッドを呼び出すほうがMap型の変数より速いです。

例えば、両方ともマップは HashMap なのですが、Map よりも HashMap のマップのメソッドを呼び出す方がコストは安く済みました。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:02

※ effectively: 事実上。

英語: Furthermore, the JIT makes the two effectively indistinguishable.

しかも、JITはそれら二つの差を効果的になくします。

さらに、JIT によりこの二つは事実上区別がつかなくなります。
---------------------
※ 翻訳されていません。

英語: Virtual method calls are expensive, much more so than instance field lookups. It's reasonable to follow common object-oriented programming practices and have getters and setters in the public interface, but within a class you should always access fields directly.

  *** 翻訳なし ***

バーチャルメソッドの呼び出しはコストが高くつきます。また、フィールド探索よりもずっとコストが掛かります。一般的なオブジェクト指向プログラミングの慣例に従って、ゲッターとセッターは public のインターフェースにするのが妥当ですが、クラス内では常に直接フィールドにアクセスするのが良いでしょう。
---------------------
※ matters: 事態。keyword が翻訳されていません。

英語: We can improve matters with the "final" keyword:

finalでこの面倒を改善することが出来ます。

以下のように、"final" キーワードを使用して事態を改善できます。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:03

※1. <clinit>の "<" と ">" もメソッド名の一部です("<" と ">"は実際は半角文字)。
※2. a class initializer method, called <clinit>: <clinit>と呼ばれるクラス初期化メソッド

英語: The compiler generates a class initializer method, called <clinit>, that is executed when the class is first used.

コンパイラはclinitをコールする初期化メソッドを作成し、クラスが最初に使用されるときに呼び出されます。

コンパイラは、クラスが最初に使用されるときに実行される、<clinit>と呼ばれるクラス初期化メソッドを生成します。
---------------------
※1. <clinit>の "<" と ">" もメソッド名の一部です("<" と ">"は実際は半角文字)。
※2. method が翻訳されていません。

英語: The class no longer requires a <clinit> method,

クラスはclinitをもはや必要としません。

クラスは<clinit>メソッドをもはや必要としません。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:04

※ "string constant" instruction の instruction が翻訳されていません。

英語: accesses to strVal will use a relatively inexpensive "string constant" instruction instead of a field lookup

strValへのアクセスはフィールド参照より安価な文字列定数を使用します。

strVal へのアクセスは、フィールド参照ではなくそれよりもコストが掛からない『文字列定数』の命令(訳注:『文字列定数』をオペランドに持つ命令)を使用して行われます。
---------------------
※1. practice: 習慣。
※2. declare が翻訳されていません。

英語: it's good practice to declare constants static final whenever possible.

可能なかぎり定数をstatic finalとするのは良い手法です。

可能であればいつでも定数を static final と宣言するのは良い習慣です。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:05

※1. known as "for-each" loop: "for each" ループとしても知られている
※2.Iterable は固有名詞。
※3. The enhanced for loop: 拡張 "for" ループ。 "for" が日本語から消えています。

英語: The enhanced for loop (also sometimes known as "for-each" loop) can be used for collections that implement the Iterable interface and for arrays.

強化されたループ(for eachとも言われる)はiterableなインターフェイスを実装するコレクションと配列のために使用できます。

"for each" ループとしても知られている、拡張 for ループは Iterable インターフェースを実装するコレクションと配列に使用できます。
---------------------
※1. 英文の内容から離れた翻訳になっています。
※2. 「・・・コレクション【にが】割り当て・・・」タイプミス

英語: With collections, an iterator is allocated to make interface calls to hasNext() and next().

iteratorインターフェイスによってコレクションにが割り当てられます。

コレクションには、hasNext() と next() へのインターフェース呼び出しを行うためのイテレータが割り当てられています。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:06

※1. counted loop: カウントループ(制御変数でループの数をカウントする昔ながらの for ループのこと)
※2. explicit: 明示的な

英語: With an ArrayList, a hand-written counted loop is about 3x faster (with or without JIT), but for other collections the enhanced for loop syntax will be exactly equivalent to explicit iterator usage.

手書きでカウントされるArrayListのループは約3倍速いです。(JITの有無に関わらず)しかし他のコレクションに対してのループ構文は正確にiteratorを使用した場合と等しいです。

ArrayList では手書きのカウントループは JIT の有無に関係なく約 3 倍速いですが、他のコレクションでは拡張 for ループ構文は明示的にイテレータを使用する場合とちょうど同じ速さです。
---------------------
※ "once for every iteration through the loop" が翻訳されていません。

英語: zero() is slowest, because the JIT can't yet optimize away the cost of getting the array length once for every iteration through the loop.

zero()は最も遅いです。なぜなら、JITが配列長を取得するためのコストを最適化することがまだ出来ないためです。

zero()は最も遅いです。なぜなら、(現在の) JIT はまだループの各イテレーションに付き一度配列長を取得するためのコストを最適化できないからです。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:08

※ "pulls everything out into local variables" が翻訳されていません。

英語: one() is faster. It pulls everything out into local variables, avoiding the lookups. Only the array length offers a performance benefit.

one()はそれより速いです。ローカル変数を参照しルックアップを避けます。array lengthだけはパフォーマンスを提供します。

one() は(zero() よりも)もっと速いです。これは、すべてをローカル変数に引っ張り出してきて、ルックアップを回避します。配列の長さだけがパフォーマンス向上をもたらします。
---------------------
※ the enhanced for loop syntax: 拡張 for ループ構文。

英語: two() is fastest for devices without a JIT, and indistinguishable from one() for devices with a JIT. It uses the enhanced for loop syntax introduced in version 1.5 of the Java programming language.

two()はJITの無い端末では最速で、JITがある端末ではone()と同等です。Java1.5で採用された強化されるループ構文を使用します。

two() は JIT が無いデバイスでは最速です。JIT があるデバイスの場合は、one() と区別が付きません。これは、Java プログラミング言語のバージョン 1.5 で導入された拡張 for ループ構文を使用しています。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:09

※ 意味的に正反対な翻訳になっています!

英語: To summarize: use the enhanced for loop by default, but consider a hand-written counted loop for performance-critical ArrayList iteration.

要約すると、パフォーマンス重視の ArrayList のイテレーションのためには、カウントされた手書きのループを考えるのではなく、デフォルトで拡張 For ループを使用してください。

要約すると、デフォルトでは拡張 For ループを使用してください。ただ、パフォーマンスが要求される ArrayList のイテレーションでは、手書きのカウントループを検討してください。
---------------------
※1. 「private inner classとして定めた内部クラス」:翻訳が変です。
※2. in the outer class の "class" が翻訳されていません。

英語: The key things to note here are that we define a private inner class (Foo$Inner) that directly accesses a private method and a private instance field in the outer class.

ここで注意すべきのは、private inner classとして定めた内部クラス(Foo$Inner)が外のプライベートメソッドとインスタンスフィールドに直接アクセスしているということです。

ここで注意すべき重要な事柄は、アウタークラスの private メソッドと private インスタンスフィールドに直接アクセスする private なイナークラス(Foo$Inner)を定義していることです。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:10

※ 部分的に翻訳されていない部分もあるので、すべて補います。

英語: The problem is that the VM considers direct access to Foo's private members from Foo$Inner to be illegal because Foo and Foo$Inner are different classes, even though the Java language allows an inner class to access an outer class' private members.

問題はJava言語として適切であったとしても、VMがFooとFoo$Innerが別のクラスなので、直接のアクセスは許可されていないと考える事です。

問題は Java 言語ではイナークラスがアウタークラスの private なメンバにアクセスするのを許されていたとしても、Foo と Foo$Inner は異なるクラスなので、Foo$Inner から Foo の private なメンバに直接アクセスするの不正であると VM 側は認識してしまうことです。
---------------------
※ access が翻訳されていません。

英語: access the mValue field or invoke the doStuff method in the outer class

アウタークラスのmValueフィールドかdoStuffメソッドを呼び出す

アウタークラスの mValue フィールドにアクセスしたり、doStuff メソッドを呼び出す
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:11

※1. As a rule of thumb: 大まかに
※2. "than integer" が翻訳されていません。

英語: As a rule of thumb, floating-point is about 2x slower than integer on Android devices.

経験上、浮動小数点はAndroidのデバイスで2倍程度遅いです。

大まかに、Android デバイスでは浮動小数点演算は整数演算よりも 2 倍程度遅いです。
---------------------
※ for arithmetic operations が翻訳されていません。

英語: absolute speed difference between those two devices is about 10x for arithmetic operations

2台の端末には10倍の絶対的な速度差があります

2 台の端末には算術演算で 10 倍の絶対的な速度差があります
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:12

※1. integers: 「整数」と翻訳した方がよいと思います。
※2. multiply: 乗算
※3. divide: 除算
※4. modulus: 剰余

英語: Also, even for integers, some chips have hardware multiply but lack hardware divide. In such cases, integer division and modulus operations are performed in software - something to think about if you're designing a hash table or doing lots of math.

また、Integerでさえ、いくつかのチップでは複数のハードウェアを持つが、ハードウェアでの分割機能を欠如しています。そのような場合、整数の分割と係数はソフトウェアで処理されます。いくつか考えるべきは、ハッシュテーブルを設計している時や、沢山の数学を行う必要がある時です。

また、整数演算についてさえ、乗算のハードウェアはあるけれども、除算のハードウェアがないチップもあります。そのような場合、整数の除算と剰余演算はソフトウェアで行われます。つまり、ハッシュテーブルを設計している時や、数学演算をたくさん行う場合は、このことを考える必要があります。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:13

※1. 前半部分の翻訳の繋がりに改善の余地があると思います。
※2. 「システムは・・・呼ぶ」のではなく「システムは・・・置き換える」と英文にあります。
※3. "for the equivalent Java" の equivalent が正しく翻訳されていない気がします。アセンブラコードで記述したものと同等のもの Java で記述したとして、その Java コードから JIT が生成するアセンブラコードが劣ることもあると述べているのだと思います。

英語: In addition to all the usual reasons to prefer library code over rolling your own, bear in mind that the system is at liberty to replace calls to library methods with hand-coded assembler, which may be better than the best code the JIT can produce for the equivalent Java.

あなたの処理を実行するよりライブラリコードを好む理由があります。通常の理由に加えて、システムは自由に手作業で作られたアセンブラコード(JITがJavaで作成できる最高のコードより良い場合がある)を呼べることを覚えておいてください。

自分でやってしまうよりもライブラリコードを選ぶ一般的な理由はいろいろとあるでしょうが、システムはライブラリメソッドへの呼び出しを自由に手作業で記述されたアセンブラコードに置き換えれることをよく覚えておいてください。そのアセンブラコードは、それと同等の Java プログラムについて JIT が生成できる最高のコードよりも良いものかもしれません。
---------------------
※1. Dlavic → Dalvik
※2. intrinsic が翻訳されていません。

英語: which Dalvik replaces with an inlined intrinsic

これはDlavicで代わりにインラインされています

Dalvik はこれをインライン展開された組み込みコード(アセンブラコード)に置き換えます
----

名前:ひさねこ|投稿日:2011/10/07 18:14

※1. file descriptor: ファイル記述子。
※2. timely は collection ではなく arrange を修飾しています。

英語: If you're allocating native resources (memory on the native heap, file descriptors, or whatever), it can be significantly more difficult to arrange timely collection of these resources.

もし、ネイティブリソース(ネイティブヒープ上のメモリ、ファイル記載子など)を割り当てると、これらのリソースのタイムリーなコレクションを取得するのはかなり難しくなります。

ネイティブヒープ上のメモリやファイル記述子など何であれ、ネイティブリソースを割り当てる場合、これらのリソースのコレクションをタイムリーに配置するのがかなり難しくなることがあります。
---------------------
※1. "your code" と "you wish to run on (rather than rely on it having a JIT)" が翻訳されていません。
※2. also は "You" ではなく "need to compile your code" を修飾しています。

英語: You also need to compile your code for each architecture you wish to run on (rather than rely on it having a JIT).

あなた自身もまたアーキテクチャごとにコンパイルを行う必要があります。

JIT に頼ることなく、実行してみたいアーキテクチャ毎に自分のコードをコンパイルする必要もあります。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:15

※ "Caliper microbenchmarking framework for Java" はフレームワークの名称。

英語: The benchmarks are built with the Caliper microbenchmarking framework for Java.

ベンチマークはJavaのマイクロベンチマークによってビルドされています。

ベンチマークは "Caliper microbenchmarking framework for Java" によってビルドされています。
---------------------
※1. "what you think you're measuring" が翻訳されていません。
※2. 「なぜならVMあなたの」→「なぜならVMはあなたの」
※3. 「最適化することが出来るので」→現在完了形("has managed to optimize")なので、最適化は終わっています。

英語: Microbenchmarks are hard to get right, so Caliper goes out of its way to do the hard work for you, and even detect some cases where you're not measuring what you think you're measuring (because, say, the VM has managed to optimize all your code away).

マイクロベンチマークは正しく測るのが難しいので、カリパスはあなたのために困難な作業をし、あなたが測っていないケースさえ見つける努力をします(なぜならVMあなたのコードを最適化することが出来るので)

マイクロベンチマークは正しく行うのは難しいのですが、Caliper はわざわざその困難な作業をやってくれます。VM はすべてコードを最適化してしまっているので、計測していると考えているものが実は計測されていない場合もあり、Caliper はそのことを検知することさえやってくれます。
---------------------

名前:ひさねこ|投稿日:2011/10/07 18:17

※1. 全体的な構文解釈に誤りがあるように思えます。例えば、冒頭の It は "to ensure ・・・ Traceview" を指しています。
※2. 早く→速く

英語: It's especially important after making changes suggested by Traceview data to ensure that the resulting code actually runs faster when run without Traceview.

それはTraceviewデータで動かしたあとにTraceview無しで動くとき、結果として生じるコードが実際に早くなるようにTraceviewデータを使うときに特に重要です。

Traceview データにより提案された変更を行った後、Traceview 無しで実行させてみて、その結果コードが実際に速く実行していることを確認することは特に重要です。
---------------------

以上です!参考になれば幸いです。

名前:kenz|投稿日:2011/10/07 23:47

またまた、ありがとうございます。
ごらんの通り私の英語力は貧弱でGoogleI/Oに向けて、
英語を勉強しながらついでにAndroidのことも勉強できて一石二鳥。という勢いで書いていましたので、親切な解説と修正をいただき、とてもありがたく思っています。
ご指摘を活かして今後はもっともっと分かりやすい訳を心がけていきたいと思っています。

コメントを投稿する

名前URI
コメント