Kiedy używać macierzy, bufora lub bezpośredniego bufora

Pytanie

Pisząc klasę Matrix do użytku z bibliotekami OpenGL, natknąłem się na pytanie, czy używać tablic Java lub strategii bufora do przechowywania danych (JOGL oferuje kopię bezpośredniego bufora dla operacji Matrix). Aby to przeanalizować, napisałem mały program testujący wydajność, który porównuje prędkości względne operacji pętlowych i masowych na macierzach vs bufory vs bufory bezpośrednie.

Chciałbym podzielić się z wami swoimi wynikami tutaj (ponieważ uważam je za raczej interesujące). Prosimy o komentarz i / lub wskazanie wszelkich błędów.
Kod można obejrzeć pod adresempastebin.com/is7UaiMV.

Uwagi

Tablica odczytu pętli jest zaimplementowana jakoA [i] = B [i] w przeciwnym razie optymalizator JIT całkowicie usunie ten kod. Rzeczywistyvar = A [i] wydaje się być prawie taki sam.

W przykładowym wyniku dla wielkości tablicy 10 000 jest bardzo prawdopodobne, że optymalizator JIT zastąpił zapętlony dostęp do tablicy implementacją podobną do System.arraycopy.

Nie ma bufora zbiorczego-> bufora jako implementacji JavaA.get (B) tak jakB. wydajność (A)dlatego wyniki byłyby takie same jak wyniki zbiorcze.

Wniosek

W prawie wszystkich sytuacjach zdecydowanie zaleca się używanie wewnętrznych tablic Java. Prędkość put / get jest nie tylko znacznie szybsza, ale JIT jest w stanie wykonać znacznie lepsze optymalizacje ostatecznego kodu.

Bufory powinnytylko być użyty, jeśliobie obowiązuje:

Musisz przetworzyćDuże ilości danych.Te dane są przeważnie lub zawszeprzetwarzane luzem.

Zwróć uwagę, że bufor buforowany ma tablicę Java, która wspiera zawartość bufora. Zaleca się wykonywanie operacji na tym buforze wstecznym zamiast pętli put / get.

Bezpośrednie bufory powinnytylko używaj, jeśli się martwiszzużycie pamięci i nigdy nie uzyskaj dostępu do danych bazowych. Są nieco wolniejsze niż bufory niebezpośrednie, dużo wolniejsze, jeśli dostęp do danych jest możliwy, ale zużywają mniej pamięci. Ponadto istnieje dodatkowy narzut przy konwersji danych nie-bajtowych (takich jak tablice float) na bajty, gdy używany jest bezpośredni bufor.

Więcej informacji można znaleźć tutaj:

Dlaczego tylko ByteBuffery są użyteczne podczas używania buforów bezpośrednichWewnętrzny narzut na NIO i to, co spowalnia buforPrzykładowe wyniki

Uwaga: Procent jest tylko dla ułatwienia czytania i nie ma prawdziwego znaczenia.

Używanie tablic o rozmiarze 16 z 10 000 000 iteracji ...
-- Array tests: -----------------------------------------

Loop-write array:           87.29 ms  11,52%
Arrays.fill:                64.51 ms   8,51%
Loop-read array:            42.11 ms   5,56%
System.arraycopy:           47.25 ms   6,23%

-- Buffer tests: ----------------------------------------

Loop-put buffer:           603.71 ms  79,65%
Index-put buffer:          536.05 ms  70,72%
Bulk-put array->buffer:    105.43 ms  13,91%
Bulk-put buffer->buffer:    99.09 ms  13,07%

Bulk-put bufferD->buffer:   80.38 ms  10,60%
Loop-get buffer:           505.77 ms  66,73%
Index-get buffer:          562.84 ms  74,26%
Bulk-get buffer->array:    137.86 ms  18,19%

-- Direct buffer tests: ---------------------------------

Loop-put bufferD:          570.69 ms  75,29%
Index-put bufferD:         562.76 ms  74,25%
Bulk-put array->bufferD:   712.16 ms  93,96%
Bulk-put buffer->bufferD:   83.53 ms  11,02%

Bulk-put bufferD->bufferD: 118.00 ms  15,57%
Loop-get bufferD:          528.62 ms  69,74%
Index-get bufferD:         560.36 ms  73,93%
Bulk-get bufferD->array:   757.95 ms 100,00%
Używanie tablic o rozmiarze 1000 z 100 000 iteracji ...
-- Array tests: -----------------------------------------

Loop-write array:           22.10 ms   6,21%
Arrays.fill:                10.37 ms   2,91%
Loop-read array:            81.12 ms  22,79%
System.arraycopy:           10.59 ms   2,97%

-- Buffer tests: ----------------------------------------

Loop-put buffer:           355.98 ms 100,00%
Index-put buffer:          353.80 ms  99,39%
Bulk-put array->buffer:     16.33 ms   4,59%
Bulk-put buffer->buffer:     5.40 ms   1,52%

Bulk-put bufferD->buffer:    4.95 ms   1,39%
Loop-get buffer:           299.95 ms  84,26%
Index-get buffer:          343.05 ms  96,37%
Bulk-get buffer->array:     15.94 ms   4,48%

-- Direct buffer tests: ---------------------------------

Loop-put bufferD:          355.11 ms  99,75%
Index-put bufferD:         348.63 ms  97,93%
Bulk-put array->bufferD:   190.86 ms  53,61%
Bulk-put buffer->bufferD:    5.60 ms   1,57%

Bulk-put bufferD->bufferD:   7.73 ms   2,17%
Loop-get bufferD:          344.10 ms  96,66%
Index-get bufferD:         333.03 ms  93,55%
Bulk-get bufferD->array:   190.12 ms  53,41%
Używanie tablic o rozmiarze 10 000 z 100 000 iteracji ...
-- Array tests: -----------------------------------------

Loop-write array:          156.02 ms   4,37%
Arrays.fill:               109.06 ms   3,06%
Loop-read array:           300.45 ms   8,42%
System.arraycopy:          147.36 ms   4,13%

-- Buffer tests: ----------------------------------------

Loop-put buffer:          3385.94 ms  94,89%
Index-put buffer:         3568.43 ms 100,00%
Bulk-put array->buffer:    159.40 ms   4,47%
Bulk-put buffer->buffer:     5.31 ms   0,15%

Bulk-put bufferD->buffer:    6.61 ms   0,19%
Loop-get buffer:          2907.21 ms  81,47%
Index-get buffer:         3413.56 ms  95,66%
Bulk-get buffer->array:    177.31 ms   4,97%

-- Direct buffer tests: ---------------------------------

Loop-put bufferD:         3319.25 ms  93,02%
Index-put bufferD:        3538.16 ms  99,15%
Bulk-put array->bufferD:  1849.45 ms  51,83%
Bulk-put buffer->bufferD:    5.60 ms   0,16%

Bulk-put bufferD->bufferD:   7.63 ms   0,21%
Loop-get bufferD:         3227.26 ms  90,44%
Index-get bufferD:        3413.94 ms  95,67%
Bulk-get bufferD->array:  1848.24 ms  51,79%

questionAnswers(2)

yourAnswerToTheQuestion