零拷贝
1、零拷贝是从操作系统的角度出发,因为内核缓冲区之间没有数据是重复的,只有kernel buffer一份数据
2、零拷贝不仅仅带来更少的数据复制,还能带来其他性能的优势,例如更少的上下文切换,更少的cpu缓存伪共享,以及无cpu校验和计算
DMA(direct memory Access):直接存储器访问
mmap内存映射和sendFile的区别
1、mmap适合小数据量读写,sendfile适合大文件传输
2、mmap需要4次上下文切换,3次数据拷贝;sendFile需要3次上下文切换,最少2次数据拷贝
3、sendFile可以利用DMA方式,减少CPU拷贝,mmap则不能(必须从内核拷贝到socket缓冲区)
标题代码实例记录:
// server端
package com.example.demo.nio.ZeroCopy;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class NewIOSever {
public static void main(String[] args) throws Exception{
InetSocketAddress inetSocketAddress = new InetSocketAddress(7001);
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
ServerSocket serverSocket = serverSocketChannel.socket();
//绑定端口
serverSocket.bind(inetSocketAddress);
//创建buffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
while (true){
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("进来的连接:" + socketChannel.getRemoteAddress());
int readCount = 0;
while (-1 != readCount){
try{
readCount = socketChannel.read(byteBuffer);
}catch (Exception ex){
break;
}
//进行倒带
byteBuffer.rewind();//position为0,mark作废
}
}
}
}
客户端
//客户端
package com.example.demo.nio.ZeroCopy;
import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
public class NewIOClient {
public static void main(String[] args) throws Exception{
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 7001));
String fileName = "interview.pdf";
//得到一个文件channel
FileChannel fileChannel = new FileInputStream(fileName).getChannel();
System.out.println("socketChannel的地址:" + socketChannel.getLocalAddress());
long startTime = System.currentTimeMillis();
//在linux下调用transferTo方法可以完成传输,在windows下,一次只能传输8M文件
//准备发送
long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);
System.out.println("发送总字节数="+transferCount+",耗时:"+(System.currentTimeMillis()-startTime));
fileChannel.close();
}
}
总结:代码主要演示由netty提供的transferTo()方法可以直接进行零拷贝,与传统IO流复制文件相比确实速度提高很多
此处注意该方法调用时windows和linux系统存在差异
(画个太阳激励自己) ☀