何时使用数组、缓冲区或直接缓冲区 [英] When to use Array, Buffer or direct Buffer

查看:97
本文介绍了何时使用数组、缓冲区或直接缓冲区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在编写用于 OpenGL 库的 Matrix 类时,我遇到了是使用 Java 数组还是使用 Buffer 策略来存储数据的问题(JOGL 为 Matrix 操作提供直接缓冲区副本).为了分析这一点,我编写了一个小型性能测试程序,用于比较数组、缓冲区和直接缓冲区上循环和批量操作的相对速度.

While writing a Matrix class for use with OpenGL libraries, I came across the question of whether to use Java arrays or a Buffer strategy to store the data (JOGL offers direct-buffer copy for Matrix operations). To analyze this, I wrote a small performance test program that compares the relative speeds of loop and bulk operations on Arrays vs Buffers vs direct Buffers.

我想在这里与您分享我的结果(因为我觉得它们很有趣).请随时发表评论和/或指出任何错误.
可以在 pastebin.com/is7UaiMV 查看代码.

I'd like to share my results with you here (as I find them rather interesting). Please feel free to comment and/or point out any mistakes.
The code can be viewed at pastebin.com/is7UaiMV.

  • 循环读取数组实现为 A[i] = B[i] 否则 JIT 优化器将完全删除该代码.实际的 var = A[i] 似乎几乎相同.

  • Loop-read array is implemented as A[i] = B[i] as otherwise the JIT optimizer will completely remove that code. Actual var = A[i] seems to be pretty much the same.

在数组大小为 10,000 的示例结果中,JIT 优化器很可能已将循环数组访问替换为类似 System.arraycopy 的实现.

In the sample result for array size of 10,000 it is very likely that the JIT optimizer has replaced the looped array access with a System.arraycopy like implementation.

没有bulk-get buffer->buffer,因为Java将A.get(B)实现为B.put(A),因此结果将与批量放置结果相同.

There is no bulk-get buffer->buffer as Java implements A.get(B) as B.put(A), therefore the results would be the same as the bulk-put results.

在几乎所有情况下,强烈建议使用 Java 内部数组.不仅放置/获取速度大大加快,JIT 还能够对最终代码执行更好的优化.

Under almost all situations it is strongly recommended to use the Java internal Arrays. Not only is the put/get speed massively faster, the JIT is as well able to perform much better optimizations on the final code.

缓冲区应该两者都适用的情况下使用:

Buffers should only be used if both the following applies:

  • 您需要处理大量的数据.
  • 该数据大部分或总是批量处理.

请注意,后备缓冲区具有支持缓冲区内容的 Java 数组.建议在这个后台缓冲区上做操作,而不是循环 put/get.

Note that a backened-buffer has a Java Array backening the content of the buffer. It is recommended to do operations on this back-buffer instead of looping put/get.

如果您担心内存使用并且从不访问底层数据,则应该使用直接缓冲区.它们比非直接缓冲区稍慢,如果访问底层数据则慢得多,但使用更少的内存.此外,在使用直接缓冲区时,将非字节数据(如浮点数组)转换为字节会产生额外的开销.

Direct buffers should only be used if you worry about memory usage and never access the underlying data. They are slightly slower than non-direct buffers, much slower if the underlying data is accessed, but use less memory. In addition there is an extra overhead when converting non-byte data (like float-arrays) into bytes when using a direct buffer.

有关更多详细信息,请参见此处:

For more details see here:

注意:百分比只是为了方便阅读,没有实际意义.

-- 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%

使用大小为 1,000 的数组和 100,000 次迭代...

-- 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%

使用大小为 10,000 的数组和 100,000 次迭代...

-- 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%

推荐答案

直接缓冲区并不是为了加速 Java 代码的访问.(如果可能的话,JVM 自己的数组实现有问题.)

Direct buffers are not meant to accelerate access from Java code. (If that were possible there was something wrong with the JVM’s own array implementation.)

这些字节缓冲区用于与其他组件接口,因为您可以将字节缓冲区写入 ByteChannel 并且您可以将直接缓冲区与本机代码(例如您提到的 OpenGL 库)结合使用.它旨在加速这些操作.使用显卡的芯片进行渲染可以在一定程度上加速整体操作,而不是补偿从 Java 代码访问缓冲区可能较慢的情况.

These byte buffers are for interfacing with other components as you can write a byte buffer to a ByteChannel and you can use direct buffers in conjunction with native code such as with the OpenGL libraries you mentioned. It’s intended to accelerate these operation then. Using a graphics card’s chip for rendering can accelerate the overall operation to a degree more than compensating the possibly slower access to the buffer from Java code.

顺便说一句,如果您测量对字节缓冲区的访问速度,尤其是直接字节缓冲区,则值得在获取FloatBuffer 查看:

By the way, if you measure the access speed to a byte buffer, especially the direct byte buffers, it’s worth changing the byte order to the native byte order before acquiring a FloatBuffer view:

FloatBuffer bufferD = ByteBuffer.allocateDirect(SIZE * 4)
                                .order(ByteOrder.nativeOrder())
                                .asFloatBuffer();

这篇关于何时使用数组、缓冲区或直接缓冲区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆