簡體   English   中英

為什么在Java中訪問對象字段比訪問數組快?

[英]Why does access to object fields is faster than to array in Java?

我期望數組是存儲數據(讀/寫)的最有效方式,但是測試卻相反。

public static class Store {

    public int field1;
    public int field2;
    public int field3;
    public int field4;
}
public static final int size = 5500000;
public static int[][] array = new int[4][size];
public static Store[] arrayStore = new Store[size];

...

for (int i = 0; i < size; ++i) {
     sum += arrayStore[i].field1;
     sum += arrayStore[i].field2;
     sum += arrayStore[i].field3;
     sum += arrayStore[i].field4;
}

VS:

for (int i = 0; i < size; ++i) {
     sum += array[0][i];
     sum += array[1][i];
     sum += array[2][i];
     sum += array[3][i];
}

[Java HotSpot(TM)SE(版本1.8.0_131-b11)32位]

我將 新int [size] [4] 更改為 新int [4] [size], 因為它占用的內存空間少得多

首先,在我的系統(Java 9.0.4 x64)上,所示的數組版本是對象版本的兩倍。 因此,您的基准測試可能是錯誤的。

但是為了將一個蘋果與另一個蘋果進行比較,我們首先重構數組版本,以便沿着第一個維度大步前進,就像在對象版本中一樣:

    for (int i = 0; i < size; ++i) {
         sum += array[i][0];
         sum += array[i][1];
         sum += array[i][2];
         sum += array[i][3];
    }

在這種情況下,由於經常檢查微小的第二維,因此它的運行速度確實較慢。

請記住,Java中沒有真正的多維數組。 new int[size][4]確實是

    int[][] array = new int[size][];
    for (int i = 0; i < size; ++i) {
        array[i] = new int[4];
    }

您可以將第一個“列”維可視化為包含指向行的指針,每行一個數組對象。 因此,每行的大小並不是真正固定的,需要在運行時進行檢查。

實際上,我們看到數組變體執行的指令幾乎是指令的兩倍:

VTUNE

那是因為所有邊界檢查。 這是為test2生成的JIT代碼的一部分:

0x4c8847b   add eax, dword ptr [r12+r8*8+0x14]
0x4c88480   add eax, dword ptr [r12+r8*8+0x18]
0x4c88485   add eax, dword ptr [r12+r8*8+0x1c]
0x4c8848a   shl r11, 0x3
0x4c8848e   mov edx, 0x1
0x4c88493   nop 
0x4c8849c   nop 
0x4c884a0   mov r8d, dword ptr [r11+rdx*4+0x10]
0x4c884a5   mov ecx, dword ptr [r12+r8*8+0xc]   # bounds checking #
0x4c884aa   lea r10, ptr [r12+r8*8]
0x4c884ae   test ecx, ecx                       # bounds checking #
0x4c884b0   jbe 0x4c88572
0x4c884b6   add eax, dword ptr [r12+r8*8+0x10]
0x4c884bb   cmp ecx, 0x1                        # bounds checking #
0x4c884be   jbe 0x4c88589                       # bounds checking #
0x4c884c4   add eax, dword ptr [r12+r8*8+0x14]
0x4c884c9   cmp ecx, 0x3                        # bounds checking #
0x4c884cc   jbe 0x4c885a1
0x4c884d2   mov r9d, dword ptr [r11+rdx*4+0x14]
0x4c884d7   mov ecx, dword ptr [r12+r9*8+0xc]   # bounds checking #
0x4c884dc   add eax, dword ptr [r12+r8*8+0x18]
0x4c884e1   add eax, dword ptr [r12+r8*8+0x1c]
0x4c884e6   mov ebx, edx
0x4c884e8   inc ebx
0x4c884ea   lea r10, ptr [r12+r9*8]
0x4c884ee   test ecx, ecx                       # bounds checking #
0x4c884f0   jbe 0x4c88574                       # bounds checking #
0x4c884f6   add eax, dword ptr [r12+r9*8+0x10]
0x4c884fb   cmp ecx, 0x1                        # bounds checking #
0x4c884fe   jbe 0x4c8858b
0x4c88504   add eax, dword ptr [r12+r9*8+0x14]
0x4c88509   cmp ecx, 0x3                        # bounds checking #
0x4c8850c   jbe 0x4c885a7                       # bounds checking #
0x4c88512   add eax, dword ptr [r12+r9*8+0x18]
0x4c88517   add eax, dword ptr [r12+r9*8+0x1c]
0x4c8851c   add edx, 0x2
0x4c8851f   cmp edx, 0x53ec5f
0x4c88525   jl 0x4c884a0
0x4c8852b   cmp edx, 0x53ec60
0x4c88531   jnl 0x4c88566

JVM一直在不斷改進,因此至少在new int[size][4]的情況下,最終將有可能對其進行優化。 現在,盡管使用多維數組時請記住這一點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM