关于何时应使用Java NIO直接缓冲区进行网络I/O的简单规则?

关于何时应使用Java NIO直接缓冲区进行网络I/O的简单规则?,java,real-time,css-selectors,nio,bytebuffer,Java,Real Time,Css Selectors,Nio,Bytebuffer,有天赋的人能用简单明了的方式解释复杂的事情吗?为了获得最佳性能,在使用Java NIO进行网络I/O时,何时应该使用direct ByteBuffers而不是常规ByteBuffers 例如:我应该读入堆缓冲区并从那里解析它,执行多个get()(逐字节),还是应该读入直接缓冲区并从直接缓冲区解析?当您只是复制数据时,直接缓冲区最好,比如从套接字复制到文件,反之亦然,因为数据不必穿过JNI/Java边界,它只是停留在JNI的土地上。如果您计划自己查看数据,那么直接缓冲区是没有意义的 为了获得最佳

有天赋的人能用简单明了的方式解释复杂的事情吗?为了获得最佳性能,在使用Java NIO进行网络I/O时,何时应该使用direct ByteBuffers而不是常规ByteBuffers



例如:我应该读入堆缓冲区并从那里解析它,执行多个get()(逐字节),还是应该读入直接缓冲区并从直接缓冲区解析?

当您只是复制数据时,直接缓冲区最好,比如从套接字复制到文件,反之亦然,因为数据不必穿过JNI/Java边界,它只是停留在JNI的土地上。如果您计划自己查看数据,那么直接缓冲区是没有意义的

为了获得最佳性能,在使用Java NIO进行网络I/O时,何时应该使用direct ByteBuffers而不是常规ByteBuffers

直接缓冲区有许多优点

  • 避免在Java和本机内存之间传递额外的数据副本
  • 如果它们被重复使用,只有使用过的页面才会变成真正的内存。这意味着您可以使它们比我需要的大得多,它们只会浪费虚拟内存
  • 您可以高效地以本机字节顺序访问多字节原语。(基本上是一条机器代码指令)
我应该读入堆缓冲区并从那里解析它,执行许多get()(逐字节),还是应该读入直接缓冲区并从直接缓冲区解析

如果您一次读取一个字节,您可能不会获得太多优势。但是,使用直接字节缓冲区,您可以一次读取2或4个字节,并一次有效地解析多个字节

[实时][选择器]


如果您正在解析实时数据,我将避免使用选择器。我发现使用阻塞NIO或忙等待NIO可以提供最低的延迟性能(假设连接数相对较少,例如多达20个)

直接缓冲区尝试连续分配内存,而不是在本地分配Java阵列。之所以要这样做,是因为它减少了I/O过程中要完成的工作量,因为本机缓冲区已准备就绪,可以按原样传递到内核,而使用非本机缓冲区需要额外的传递。@veer这是“按部就班”的解释。我在寻找更多的规则。最终,您必须将直接缓冲区读入Java空间,因此迟早会跨越内核边界。@veer direct和heap ByteBuffers在内存中是连续的。正如其他人所说,将(大)文件读入缓冲区时,直接缓冲区应该更好,由于堆缓冲区没有绝对地址,因此可能需要首先将缓存到其他位置。使用直接缓冲区还有一个好处,那就是允许完全本地IO操作(甚至可能是异步的),而vm不必做任何事情。最后你必须看看数据,是的,这是我的观点和怀疑。你觉得怎么样?@JohnPristine从直接缓冲区一个接一个地复制字节肯定会很痛苦,但是从直接缓冲区复制任何东西都是痛苦的,这就是为什么我说要避免它,除非你只是在通道之间复制,在这里,您可以使用相同的缓冲区,并且根本不必取出数据。是否使用JNI是特定于实现的。AFAIK Android使用本机JNI调用,直接ByteBuffer速度较慢。HotSpot和OpenJDK将其视为一种内在特性,因此没有JNI参与提高direct ByteBuffers的速度。@PeterLawrey我一直从您那里读到这篇文章,但我不认为如果JNI空间而不是Java空间中不存在“direct”缓冲区,如何满足“direct”缓冲区的契约。您所说的“忙碌等待NIO”是什么意思?你至少要在一个无限(忙碌的旋转)循环中执行selectNow,对吗?我甚至试着不做selet就从通道中读取数据,但最终数据停止了或轮询SocketChannel数组。您不需要选择器。;)我正试图做到这一点,但有趣的是,我的频道在一段时间后停止接收数据。我必须再次选择:(哦,我正在检查isReadable()…让我再试一次…天哪!!!2微秒增益!!!!你是最棒的,彼得!总有一天我会为你工作。:)增益不止这些,因为你没有放弃CPU。这意味着代码、分支预测和数据的缓存仍然是热的。i、 e.它的运行速度也将提高2-3倍。