FileChannel主要进行文件IO的操作,下面主要分析write()的整个过程,read()和write()是相同的。
概要
write()/read()时:
- 如果传入的是DirectBuffer,则不需要进行数据复制,最后通过write系统调用完成IO。
- 如果传入的是非DirectBuffer,则先从本线程的DirectBuffer池中得到一个满足(size能容纳所有数据)的Buffer,之后进行数据复制,并使用DirectBuffer参与write系统调用完成IO。
对于第二种情况,数据复制会引起效率。如果业务代码再不重复利用所传入的非DirectBuffer,则会增加GC频率。
第二种情况,线程里有一个DirectBuffer池,使得DirectBuffer可以重复利用。这样不仅可以减小DirectBuffer的新建和释放开销,而且可以减小GC频率。这给我们以借鉴,我们在编写业务代码时页应该这样处理。
下面分析具体的源码。
源码
sun.nio.ch.FileChannelImpl.write()
sun.nio.ch.IOUtil.write()
接上面,sun.nio.ch.Util.getTemporaryDirectBuffer()。
下面代码说明了每个线程维持了一个DirectBuffer池,当使用的是Heap类型的Buffer进行IO时,需要先从池中得到一个DirectBuffer,之后还有进行数据复制等,并使用DirectBuffer参与系统调用完成IO。
sun.nio.ch.IOUtil.writeFromNativeBuffer()
sun.nio.ch.FileDispatcherImpl.writeFromNativeBuffer()
接上面,native调用:
所以最后,通过系统调用完成IO.操作系统调用接口的原型是: