transferTo 常被称为「零拷贝」。它到底比普通的 read/write 快多少、省下什么?这篇在一台 macOS 机器上把 1 GB 文件发给另一个进程的 socket,量时间与 CPU,并与缓冲区大小、mmap、Files.copy 对比。
read/write,8 KB 堆缓冲区 耗时中位 0.73 s(1399 MB/s),发送进程 user 0.23 s + sys 0.63 s,最大常驻内存 49 MB;接收端收到的字节数全部正确:True read/write,64 KB 直接缓冲区 耗时中位 0.31 s(3342 MB/s),发送进程 user 0.08 s + sys 0.30 s,最大常驻内存 47 MB;接收端收到的字节数全部正确:True read/write,1 MB 直接缓冲区 耗时中位 0.20 s(5131 MB/s),发送进程 user 0.05 s + sys 0.20 s,最大常驻内存 45 MB;接收端收到的字节数全部正确:True FileChannel.transferTo(一次要求发整个文件) 耗时中位 0.17 s(6063 MB/s),发送进程 user 0.04 s + sys 0.17 s,最大常驻内存 44 MB;接收端收到的字节数全部正确:True FileChannel.transferTo(每次最多 1 MB) 耗时中位 0.18 s(5685 MB/s),发送进程 user 0.04 s + sys 0.18 s,最大常驻内存 44 MB;接收端收到的字节数全部正确:True map 成 64 MB 一段再 write 耗时中位 0.27 s(3780 MB/s),发送进程 user 0.05 s + sys 0.27 s,最大常驻内存 1120 MB;接收端收到的字节数全部正确:True
文件 1073741824 字节,transferTo 调用 1 次;单次返回最小 1073741824 字节,最大 1073741824 字节;总计 1073741824
FileChannel.transferTo(文件) 最好一次 0.25 s(4295 MB/s),目标文件大小 1073741824 字节 FileChannel.transferFrom 最好一次 0.30 s(3533 MB/s),目标文件大小 1073741824 字节 Files.copy 最好一次 0.58 s(1859 MB/s),目标文件大小 1073741824 字节 read/write 1 MB 直接缓冲区 最好一次 0.34 s(3147 MB/s),目标文件大小 1073741824 字节