Java NIO Buffer

  Java NIO (Non Blocking IO 或者 New IO)是一种非阻塞IO的实现。NIO通过Channel、Buffer、Selector几个组件的协同实现提升IO效率的目的。而ByteBuffer是其中最基础的一种Buffer实现。

阻塞 or 非阻塞

  阻塞/非阻塞,同步/异步是两组非常容易产生混淆的概念。

同步/异步:是从消息通信机制的划分,如果调用者在没有得到结果前“调用”不返回,则是同步的。而如果调用发出后,调用直接返回,结果由被调用者通过某种机制(通知、状态)返回,则是异步的。

阻塞/非阻塞:是站在调用者的角度,描述调用者在等待调用结果时的状态。阻塞是指,在得到返回结果前,当前线程会被一直挂起,只有在得到结果后才返回。非阻塞是指,调用不会阻塞当前线程,可能不会得到想要的结果,但会立刻返回。

以找老板签报销单为例:

如果去老板工位发现老板不在,你一直站在旁边等老板回来签字才回去,那你就是阻塞的(好蠢。。。);

如果去老板工位发现老板不在,你立马回来继续撸代码,过会又跑去看看老板在不在,如果不在又回来喝口水。。。那这个过程你就是非阻塞的(也有点蠢。。。);

而上述两个过程中,“通信机制”都是同步的。而:

如果,你跑过去找老板签字,老板说放这吧,过会老板把签好的报销单交给你,那这次交互过程就是异步的(想得美。。。);

可见JAVA NIO是非阻塞式的IO,是同步的IO机制。

Buffer的结构

Buffer通过position,limit,capacity三个变量管理内容。其中:capacity标记Buffer总容量大小;position标识当前可读或者可写的初始位置;limit标记当前可读或者可写的极限位置,当Buffer处于write模式时,limit=capacity,当切换至Read模式时,limit为对应写模式时的position。三者满足:position <= limit <= capacity;一种Buffer从写模式切换至读模式的示意如下图:

Flip,ClearRewind

Clear操作,置position=0, limit=capacity,将Buffer置于写模式;

Flip操作,置limit=last_position, position=0,将Buffer置于读模式;

Rewind操作,置position=0, limit不变,使得可以重新读取Buffer中的内容。

 

HeapByteBuffer , Direct ByteBuffer MappedByteBuffer

ByteBuffer本质是一块内存区域。对于ByteBuffer,可以通过allocate(int)和allocateDirect(int)分别分配Heap和Direct Buffer。ByteBuffer持有仅对Heap Buffer有效的一个字节型数组:

final byte[] hb;                  // Non-null only for heap buffers

可见HeapByteBuffer是直接分配在堆上的,可以简单理解为byte[]的一种封装。

而Direct Buffer不直接分配在堆上,其不受GC管理(而指向这块内存的Java对象是受GC管理的,只有GC回收了这个对象,操作系统才会释放Direct Buffer的内存空间)。

由于Direct Buffer由系统直接管理,其读写的消耗小于在堆上进行读写(减少了从系统至程序内存空间的拷贝)。实际上每次使用ByteBuffer进行读写时,都会临时开辟一段DirectBuffer(JDK实现上对其做了池化,避免了频繁创建和释放DirectBuffer带来的高系统调用消耗),将ByteBuffer中的内容拷贝进其中,再进行后续操作,多了一步Buffer间的拷贝操作。所以对于重复使用的Buffer,使用Direct Buffer的优点显而易见。

但是创建和释放Direct Buffer的代价则高于Heap Buffer(系统函数的直接调用),同时不当地使用DirectBuffer更容易引起内存泄漏。

MappedByteBuffer是一种DirectByteBuffer,而其内容是一个文件的全部或者部分映射。由于MappedByteBuffer对进行了文件进行了内存映射,避免了读写时进行write/read系统调用,所有在大文件读写方面具有极高的性能。但是其同样存在DirectByteBuffer存在的问题,同时涉及文件操作,文件的关闭也依赖于垃圾回收。

对上述三种Buffer进行测试对比,分别读写大小为1M,256M和1G的文件(过小的文件并没有性能上的明显差异),结果如下:

可见,当文件较小时三者并没有明显的性能差异。而在进行大文件的读写时MappedByteBuffer表现出了明显的性能优势。同时可以看到Direct和Heap之间并没有明显的差异。

最新文章

  1. 浅析jquery ajax异步调用方法中不能给全局变量赋值的原因及解决方法(转载)
  2. Sql Server R2还有备份数据库错误
  3. Jmeter基础之---jmeter基础概念
  4. 0003 64位Oracle11gR2不能运行SQL Developer的解决方法
  5. 7 天玩转 ASP.NET MVC — 第 1 天
  6. IBM V7000
  7. HDU 3829 - Cat VS Dog (二分图最大独立集)
  8. JSON.stringify
  9. VC6.0打开或者添加工程文件崩溃的解决方法
  10. [转]CentO下限制SSH登录次数
  11. Swift - 将表格UITableView滚动条移动到底部
  12. 对类对象使用new时地址分配的情况
  13. MyBatis SQL处理大于、小于号
  14. 笔记:Struts2 拦截器
  15. STM32 基DMA的DAC波形发生器
  16. Laravel框架中打印sql
  17. 企业BGP网络规划案例(四)
  18. m3u8转码
  19. NOI1999 生日蛋糕
  20. Oracle 11.2.0.4.0 Dataguard部署和日常维护(2)-Datauard部署篇

热门文章

  1. .net的retrofit--WebApiClient库深入篇
  2. 【ASP.NET Core分布式项目实战】(一)IdentityServer4登录中心、oauth密码模式identity server4实现
  3. MIPI协议-DSI
  4. Mysql与PostgreSQL小pk
  5. Mysql ibd文件恢复指南
  6. Codility:Titanium 2016 challenge:BracketsRotation
  7. More is better(并查集)
  8. VS2012 TFS解决离职后代码遗留未迁入问题
  9. ucosii --任务就绪表
  10. docfx(二)