Jvm 为什么java.nio.FileChannel transferTo()和transferFrom()更快???它使用DMA吗?

Jvm 为什么java.nio.FileChannel transferTo()和transferFrom()更快???它使用DMA吗?,jvm,nio,dma,irq,filechannel,Jvm,Nio,Dma,Irq,Filechannel,为什么在某些JVM/OS组合上,java.nio.FileChannel transferTo()和transferFrom()比逐字节传输(基于流或使用ByteBuffer)快 这些方法是否使用直接内存访问(DMA)而不是为每个字节传输发出中断请求(IRQ)?FileChannel API中有一些解释 This method is potentially much more efficient than a simple loop that reads from the source chan

为什么在某些JVM/OS组合上,java.nio.FileChannel transferTo()和transferFrom()比逐字节传输(基于流或使用ByteBuffer)快


这些方法是否使用直接内存访问(DMA)而不是为每个字节传输发出中断请求(IRQ)?

FileChannel API中有一些解释

This method is potentially much more efficient than a simple loop that reads from the source channel and writes to this channel. Many operating systems can transfer bytes directly from the source channel into the filesystem cache without actually copying them.

顺便说一句,transferTo()和transferFrom()都是抽象的,因此这取决于实际实现

它确实使用DMA/Zero copy,因此保存了从“from”缓冲区到CPU的传输,然后再从CPU到“to”缓冲区的传输。要获得更详细的解释,请阅读以下文章中IBM的文章,关于zero copy

作者解释说,新方法在Linux上更有效,因为它们减少了上下文切换,减少了从内核到应用程序以及从内核到应用程序的不必要的缓冲区复制

这些方法是否使用直接内存访问(DMA)而不是针对每个字节传输发出中断请求(IRQ)

具体细节取决于实际实现,不需要使用任何特定机制。这在
转移到
的文档中有所暗示(强调):

此方法可能比从该通道读取并写入目标通道的简单循环效率更高许多操作系统可以直接将字节从文件系统缓存传输到目标通道,而无需实际复制它们

“可能”、“很多”。。。所以没有保证

假设使用该方法可能更有效(如果只是稍微有效的话),这是有道理的,因为您允许JVM通过本机代码进行快捷操作(如果使用支持的通道类型)。他们描述的“简单循环”工作原理如下:

ByteBuffer buf = ByteBuffer.allocateDirect(BUF_SIZE);
while ( /* read more condition */ ) {
  source.read(buf);
  buf.flip();
  target.write(buf);
  buf.compact();
}
请注意,尽管这个代码段使用直接缓冲区,但您仍然需要使用Java进行缓冲区管理(读、翻转、写、压缩)。一个优化编译器可能能够省略其中的一些,但它可能不会

但是,使用
transferTo
/
transferFrom
,让JVM决定如何传输字节。如果平台对此类传输具有本机支持,那么它可能可以在不创建中间缓冲区的情况下实现这一点。如果没有这样的支持

示例:假设SocketChannel被告知通过
transferFrom
直接从文件通道读取数据。最近从中读取了FileChannel,其内容位于OS文件缓存中。SocketChannel可以直接指向操作系统文件缓存并从那里开始传输,而不是将字节读取并复制到缓冲区中。至少消除了一轮复制


现在进一步假设套接字(A)实际上连接到其他一些本地进程,例如使用一种称为SocketChannel B的管道。当B开始读取从A获得的数据时,它实际上可能再次直接从OS文件缓存读取。如果B只是使用
传输到
到另一个频道。。。你明白了。

谢谢你的贡献。我知道我的问题应该得到RTFM式的回答。让我恼火的是javadoc太模糊了,所以如果有人对JVM实现细节有深入的了解,能够在这个问题上提供更清晰的信息,那就太好了。我想DMA与IRQ的问题不仅与操作系统有关,也与硬件有关……本文中提到的所有磁盘传输都使用DMA,而不仅仅是
transferFrom/To()
。IRQ用于磁盘传输,然后通过DMA完成。这不是NIO或Java独有的:这是操作系统几十年来的工作方式。这不是一个真正的问题。