2017-09-07 63 views
0

編輯:所以,這隻發生在android上,在桌面上的結果幾乎相同,但在Android醜陋的代碼是10倍更快。在Mac上測試android 4.4(samsung galaxy s4),android 8(nexus 6p),android模擬器。安卓方法調用性能

我的Android程序的重構代碼後,我注意到,該方法調用是非常性能昂貴。比方說,我有一個類

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; 
    } 
} 

和消氣劑從塊陣列獲取數據:

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; 
} 

所以,一個簡單的得到測試給了我這些結果:

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 

但是如果我直接從陣列中獲取數據 - 它的速度快了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 

這段代碼不可讀也不靈活,但是在使用它時,我的程序在1.5秒內運行init方法,並且在使用方法時 - 它在9秒內運行!如何在沒有醜陋的複製粘貼的情況下實現良好的表現?

+3

通常:https://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java – GhostCat

+0

好的,時間學習如何做基準:)但即使沒有基準,我可以在第二種情況下立即看到結果,而在第一種情況下(我使用方法),我需要等待。 – user3470643

回答

0

Android虛擬機似乎缺少桌面JRE的HotSpot引擎的某些優化,可能是自動內聯調用。如果這是真的,你必須減少方法調用的次數。

一些想法:

  • 內嵌的getCoordinateOffset()getBlockId()方法爲Chunk.getByteFromArray() - 從您的代碼段,我沒有看到有ChunkGetter類的理由。在外層,你仍然有x/y/z抽象,並且它只在實現代碼getByteFromArray()

  • 內部變得「難看」爲什麼你將一個邏輯上的3維數組表示爲線性數組,從而使奇怪的索引計算是必要的?直接使用三維陣列消除了對特殊獲得者的需求,並且可能相當快。

  • 你的嵌套循環有效地遍歷你的線性化數組。相反,你可以做一個單一的循環for (int i=0; i<chunkArray.length; i++)。沒有x/y/z抽象,但可能比你更快的版本更快。

也許這些提示中的一些可能會有所幫助 - 只有基準測試才能說明問題,並且您決定在可讀性和速度之間進行權衡。

+0

謝謝你的回答!我簡化了我的代碼以更好地描述我的問題。在真正的程序中,我幾乎沒有實現Chunk和ChunkGetter用於不同的目的。我最終在性能至關重要的地方使用了內聯方法。 – user3470643