2017-09-07 8 views
0

編集:これはアンドロイドでのみ起こりますが、デスクトップの結果はほぼ同じですが、Androidの醜いコードでは10倍高速です。アンドロイド4.4(samsung galaxy s4)、アンドロイド8(nexus 6p)、Macのアンドロイドエミュレータでテストされています。android method call performance

私が気づいた私のアンドロイドプログラムのコードをリファクタリングした後、そのメソッド呼び出しは非常に高価です。

private void runTest() { 
    Chunk chunk = new Chunk(); 
    long start = System.nanoTime(); 
    for (int x = 0; x < 16; x++) { 
     for (int z = 0; z < 16; z++) { 
      for (int y = 0; y < 256; y++) { 
       byte id = chunk.getByteFromArray(x, y, z); 
      } 
     } 
    } 
    LOG("test took: " + (System.nanoTime() - start)/1000000 + " ms"); 
} 
first call: test took: 19 ms 
second call: test took: 16 ms 
third call: test took: 17 ms 

public ChunkGetter() { 

} 

public byte getBlockId(int x, int y, int z, byte[] blocksByteArray) { 
    return blocksByteArray[getCoordinateOffset(x, y, z)]; 
} 

public static int getCoordinateOffset(int x, int y, int z) { 
    return x * 256 * 16 + z * 256 + y; 
} 

ので、シンプルになっテストは私にこれらの結果を与えた:私はチャンク配列からデータを取得するためのクラス

public class Chunk { 
private byte[] chunkArray; 
private ChunkGetter chunkGetter; 

public Chunk() { 
    chunkArray = new byte[65536]; 
    chunkGetter = new ChunkGetter(); 
} 

public byte getByteFromArray(int x, int y, int z) { 
    return chunkGetter.getBlockId(x, y, z, chunkArray); 
} 

public byte[] getChunkArray() { 
    return chunkArray; 
    } 
} 

とゲッターを持っている、と言うことができますしかし、アレイから直接データを取得すると、20倍高速です。

private void runTest() { 
    Chunk chunk = new Chunk(); 
    byte[] chunkArray = chunk.getChunkArray(); 
    long start = System.nanoTime(); 
    for (int x = 0; x < 16; x++) { 
     for (int z = 0; z < 16; z++) { 
      for (int y = 0; y < 256; y++) { 
       byte id = chunkArray[x * 256 * 16 + z * 256 + y]; 
      } 
     } 
    } 
    LOG("test took: " + (System.nanoTime() - start)/1000000 + " ms"); 
} 
first call: test took: 1 ms 
second call: test took: 1 ms 
third call: test took: 1 ms 

このコードは読み込み不能で、柔軟ではありませんが、私のプログラムはinitメソッドを1.5秒で実行し、メソッドを使用すると9秒で実行されます!醜いコピー貼り付けなしでいいパフォーマンスを達成するにはどうすればいいですか?

+3

通常:ベンチマーク行う方法を学ぶためhttps://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java – GhostCat

+0

[OK]を、時間:)しかし、ベンチマークがなくても、2番目のケースではすぐに結果を見ることができますが、最初は(メソッドを使用する場合は)待つ必要があります。 – user3470643

答えて

0

Android仮想マシンにはデスクトップJREのHotSpotエンジンの最適化、つまり自動呼び出しの機能が不足しているようです。そうだとすれば、メソッド呼び出しの数を減らす必要があります。

いくつかのアイデア:

  • インラインChunk.getByteFromArray()getCoordinateOffset()getBlockId()方法 - あなたのコードスニペットから、私はChunkGetterクラスを持つ理由が表示されません。外側のレイヤーでは、引き続きx/y/z抽象化が行われ、実装コード内でのみ「醜い」と表示されますgetByteFromArray()

  • なぜ論理的な3次元配列を線形配列奇妙なインデックスの計算が必要なのですか? 3次元配列を直接使用すると、特別なゲッターの必要がなくなり、かなり高速になる可能性があります。

  • ネストループは、線形化された配列を効果的にトラバースします。代わりに、単一のループfor (int i=0; i<chunkArray.length; i++)を実行できます。 x/y/z抽象化はありませんが、おそらくあなたの高速版よりも高速です。

たぶん、これらのヒントのいくつかは役立つかもしれない - 唯一のベンチマークでは教えてくれます、そして、あなたは読みやすさとスピード(のビュー)との間のトレードオフを決定します。

+0

ありがとうございました!私は私の質問をより良く記述するためにコードを単純化しました。実際のプログラムでは、私はChunkとChunkGetterを別の目的で少ししか実装していません。私は、パフォーマンスが非常に重要な場所でインライン・メソッドを使用することになりました。 – user3470643