1 - 传统IO的性能问题
多次内存复制
不管是磁盘IO还是网络IO
- 数据总是先从硬件设备复制到内核空间
- 再从内核空间复制到用户空间
这就发生了两次数据拷贝和上下文切换(内核态和用户态的一次切换就是一次上下文切换),这就降低了性能。
阻塞
传统IO在没有数据可读时,读操作就会被挂起,用户线程会一直阻塞。当有大量这样的线程阻塞时,这些线程会不断的抢夺CPU资源,导致大量的CPU上下文切换,增加了系统的开销。
2 - 如何解决性能问题
jdk1.4发布的NIO,优化了内存复制和阻塞导致的性能问题,JDK1.7 又发布了 NIO2,提出了从操作系统层面实现的异步 I/O。
2.1 - 使用Buffer优化读写操作
NIO提出了Buffer和Channel的概念。
Buffer:一块连续的内存空间,是NIO读写数据的中转地。
Channel: 表示数据的源头或者目的地。用于从Buffer中读取和写入数据
传统IO和NIO最大的区别之一就是,传统IO面向流,NIO面向Buffer。使用Buffer,Channel可以将数据一次性写入或者读取。
2.2 - 减少数据复制
减少数据的复制有两个方面:
- 减少用户空间内的内存复制。使用DirectBuffer
- 减少用户空间和内核空间之间的内存复制。使用MappedByteBuffer
NIO提供了DirectBuffer,用于直接访问物理内存。和普通Buffer的区别:
- 普通Buffer分配的事JVM堆内存
- DirectBuffer分配的是物理内存(也称为堆外内存和非堆内存)
前面我们提到过,数据要写入到外部设备,需要先从用户空间复制到内核空间,再由内核空间复制到硬件设备。但是在用户空间中,还存在另一个数据复制。就是从堆内存复制到非堆内存。这个过程是通过DirectBuffer来实现的。

Java使用直接内存进行数据拷贝的原因:减少堆的GC压力。如果直接使用堆内存进行数据拷贝,在数据量比较大时,堆的GC压力也是比较大的。
2.3 - 避免阻塞,优化IO操作
IO模型:使用IO多路复用
线程模型:主从Reactor线程模型
