1

私は初めてAndroidアプリの最適化について真剣に考える必要があります。

検索しましたが、検索すればするほど混乱します。JavaおよびJVMコンポーネントのそれぞれがWRTJAVACバイトコードとDalvikバイトコードを最適化する方法を説明する優れたドキュメントを知っている人はいますか?そのほとんどはDalvikによって行われているため、私から「ブラックボックス化」されていますか?一見の価値がありますか?

いくつかの些細な例。

SharedPreferences settings = getSharedPreferences(MY_PREFERENCES, MODE_PRIVATE);
SharedPreferences.Editor prefEditor = settings.edit();
prefeditor.putString("FOO", "BAR"); 
prefEditor.commit();

vs

getSharedPreferences(MY_PREFERENCES, MODE_PRIVATE).settings.edit().putString("FOO","BAR").commit();

また

int a, b, c;

a = 2;
b = 3;

c = sum(a,b);

int sum(int x, int y){return x + y;}

vs

c = a + b;

私が尋ねる理由は、読みやすさと保守性とパフォーマンスの間のトレードオフを理解することです。標準的な答えは「測定する」ことですが、それを超えて、複雑なコードに戻ってメトリックに基づいてリファクタリングするのではなく、パフォーマンスを向上させることができる場所を事前に考えています。もちろん、とにかく測定してプロファイルを作成しますが、私の質問は理解についてです。

私は「そこに行って、書いて、測定して、気を悪くしないでください」を受け入れるのに十分な心を開いています!

洞察をありがとう。

4

2 に答える 2

2

Android アプリケーションの場合、コードは 2 つのコンパイル/最適化パスを通過します。1 つ目は、Java コードを Java バイトコードにコンパイルするときに、javac によって実行されます。2 つ目は、Java バイトコードを dalvik バイトコードに変換するときに、dx によって実行されます。

どちらによって実行される最適化について説明しているドキュメントにも精通していません。ただし、どちらもオープン ソース (javac の場合は openjdk 経由) であるため、理論的には両方を調べて、それらがどのような最適化を行っているかを理解することができます。

ただし、あなたの例は実際にはコンパイラレベルの最適化とは何の関係もありません。たとえば、dx がレジスタを最適に割り当てる方法を知っていても、パフォーマンスの高い Java コードの書き方を理解するのに役立つとは思いません。

あなたが言及した 2 つのセットの例については、両方のセットの例で 2 つのことを試すことをお勧めします。


1.分解する

最初に、dalvik バイトコードを逆アセンブルし、違いを調べます。単純に命令を数えただけでは何もわかりませんが、場合によっては、一方が他方よりも速いことが明らかです。

たとえば、最初の一連の例では、2 番目のスニペットに追加の命令が含まれていることを除いて、両方のスニペットのバイトコードはほぼ同じです。したがって、最初のスニペットは明らかにパフォーマンスが優れていますが、パフォーマンスの違いはごくわずかです。

invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;
invoke-interface {v0}, Landroid/content/SharedPreferences$Editor;->commit()Z

対。

invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences$Editor;->putString(Ljava/lang/String;Ljava/lang/String;)Landroid/content/SharedPreferences$Editor;
move-result-object v0
invoke-interface {v0}, Landroid/content/SharedPreferences$Editor;->commit()Z

2 つの Java スニペットをよく見ると、この追加の指示は理にかなっています。最初の例では、putString の戻り値は無視され、putString を呼び出したのと同じ値で commit が呼び出されます。2 番目のスニペットでは、putString() によって返された値に対して clone() が呼び出されます。これには、戻り値を保存するために dalvik バイトコードで追加の操作が必要です。つまり、そこに表示される追加の move-result-object 命令です。

私たちプログラマーは、putString メソッドの戻り値が、呼び出されているオブジェクトと同じであることを知っています。ただし、コンパイラはこれを知ることも、想定することもできません。


2.測定

あなたができる2番目のことは、あなたが言及したように、実際にそれらをプロファイリングしてパフォーマンスを測定することです. しばらくすると、パフォーマンスを向上させるためにできることの種類を感じ始めるはずです。

于 2012-10-06T18:28:48.470 に答える
0

プログラムに最適化を必要とする特定のボトルネックはありますか? そうでない場合は、何もしないでください。

于 2012-10-06T08:21:44.580 に答える