磁盘数据发送到网络的拷贝过程
磁盘数据发送到网络的拷贝过程
传统方式的4次拷贝
1
2
3
4┌─────────┐ ┌──────────┐ ┌─────────┐ ┌──────────┐ ┌─────────┐
│ 磁盘 │ -> │ 内核缓冲区│ -> │ 用户缓冲区│ -> │socket缓冲区│ -> │ 网卡 │
└─────────┘ └──────────┘ └─────────┘ └──────────┘ └─────────┘
拷贝1 拷贝2 拷贝3 拷贝4详细解释每次拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 示例代码
File.read(fileDesc, buf, len); // 读取文件
Socket.send(buf, len); // 发送数据
过程解析:
第1次拷贝:DMA拷贝
- 由DMA控制器完成
- 将磁盘数据拷贝到内核缓冲区
- 不需要CPU参与
第2次拷贝:CPU拷贝
- 由CPU完成
- 将数据从内核缓冲区拷贝到用户缓冲区(如JVM堆)
- read()系统调用的结果
第3次拷贝:CPU拷贝
- 由CPU完成
- 将数据从用户缓冲区拷贝到socket缓冲区
- write()系统调用的过程
第4次拷贝:DMA拷贝
- 由DMA控制器完成
- 将socket缓冲区的数据拷贝到网卡
- 准备通过网络发送上下文切换
1
2
3
4
5
6
7涉及的上下文切换:
1. read()调用:用户态 -> 内核态
2. read()返回:内核态 -> 用户态
3. write()调用:用户态 -> 内核态
4. write()返回:内核态 -> 用户态
总计:4次上下文切换性能影响
1
2
3
4
5
6
7
8
9资源消耗:
- CPU时间:用于数据拷贝和上下文切换
- 内存带宽:多次数据拷贝
- 延迟增加:每次上下文切换大约需要1-10微秒
示例计算(发送1MB数据):
- 数据拷贝:~10ms
- 上下文切换:~4-40微秒
- 总耗时:>10ms对比零拷贝
1
2
3
4
5
6
7
8
9
10
11零拷贝方式:
┌─────────┐ ┌──────────┐ ┌─────────┐
│ 磁盘 │ -> │ 内核缓冲区│ -> │ 网卡 │
└─────────┘ └──────────┘ └─────────┘
DMA拷贝 DMA拷贝
优势:
- 只有2次DMA拷贝
- 不需要CPU拷贝
- 减少上下文切换
- 降低延迟和CPU使用率