一、零拷贝概念
- 传统IO将文件通过socket写出的过程:
内部工作流程如下:
NIO优化的处理:
大部分步骤 与传统IO相同,但程序使用的是DirectByteBuffer,将堆外内存映射到JVM中直接使用
- 使用零拷贝(transferTo/transferFrom)
* linux2.1
特点:
1.只发生了下次用户态到内核态的转换
2.数据只拷贝了3次
* linux2.4
特点:
1.只发生了一次用户态到内核态的转换
2.数据只拷贝了2次
二、总结:
零拷贝的优点:
1.更少的用户态与内核态的切换
2.不利用CPU计算,减少CPU缓存伪共享
3.零拷贝适合小文件传输:因为小文件占用内核内存空间小,拷贝后在内核内存空间中的数据可以及时清空,不影响其他程序的文件的传输
三、速度测试
文件大小:1.46 GB (1,568,946,426 字节)
- 使用transferTo零拷贝,代码如下,耗时12116ms
public static void main(String[] args) throws IOException { long start=System.currentTimeMillis(); FileChannel inputChannel=new FileInputStream(new File("E:\\video\\第1阶段.zip")).getChannel(); FileChannel outChannel=new FileOutputStream(new File("E:\\video\\第1阶段1.zip")).getChannel(); inputChannel.transferTo(0,inputChannel.size(),outChannel); System.out.println(System.currentTimeMillis()-start); }
- 使用阻塞io,代码如下,耗时19464ms,代码如下:
public static void main(String[] args) throws IOException { long start=System.currentTimeMillis(); FileInputStream inputstream=new FileInputStream(new File("E:\\video\\第1阶段.zip")); FileOutputStream outStream=new FileOutputStream(new File("E:\\video\\第1阶段1.zip")); int bytesWritten = 0; int byteCount = 0; byte[] bytes = new byte[1024]; while ((byteCount = inputstream.read(bytes)) != -1) { outStream.write(bytes,0, byteCount); } inputstream.close(); outStream.close(); System.out.println(System.currentTimeMillis()-start); }
性能提升:37.75%