Java高并发网络编程之NIO非阻塞网络编程
NIO非阻塞网络编程
JAVA NIO
始于Java1.4,提供了新的JAVA IO操作非阻塞API。
用意是替代Java IO和Java Networking相关的API。
三大核心组件:
- Buffer缓冲区
- Channel通道
- Selector选择器
Buffer缓冲区
缓冲区本质上是一个可以写入数据的内存块(类似于数组),然后可以再次读取。此内存块包含在NIO Buffer对象中,该对象提供一组方法,可以更轻松地使用内存块。
相比较直接对数组的操作,Buffer API更加容易操作和管理。
使用Buffer进行数据写入和读取,需要进行如下四个步骤:
- 将数据写入缓冲区
- 调用buffer.flip(),转换为读取模式 flip:翻转
- 缓冲区读取数据
- 调用buffer.clear()或buffer.compact()清除缓冲区
Buffer工作原理
Buffer三个重要属性:
- capacity容量:作为一个内存块,Buffer具有一定的固定大小,也称为“容量”
- position位置:写入模式时代表写数据的位置。读取模式时代表读取数据的位置
写模式:从什么地方开始写
读模式:从什么地方开始读 - limit限制:写入模式,限制等于buffer的容量。读取模式下,limit等于写入的数据量
写模式:能写到什么位置
读模式:能读到什么地方
ByteBuffer内存类型
ByteBuffer为性能关键型代码提供了直接内存(direct堆外)和非直接内存(heap堆)两种实现。
堆外内存获取的方式:ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(noBytes);
好处:
-
进行网络IO或者文件IO时比heapBuffer少一次拷贝。(file/socket—OS memory—jvm heap)
GC会移动对象内存,在写file或socket的过程中,JVM的实现中,会先把数据复制到堆外,再进行写入。 -
GC范围之外,降低GC压力,但实现了自动管理。DirectByteBuffer中有一个Cleaner对象
(PhantomReference),Cleaner被GC前会执行clean方法,触发DirectByteBuffer中定义的Deallocator
PS:堆外内存为直接内存,堆内存为JVM管理的内存(GC会影响到这部分内存的地址)
建议:
- 性能确实可观的时候才去使用;分配给大型、长寿命;(网络传输、文件读写场景)
- 通过虚拟机参数MaxDirectMemorySize限制大小,防止耗尽整个机器的内存;