关闭

Java 学习系列:ByteBuffer

标签: javanio
280人阅读 评论(0) 收藏 举报
分类:

ByteBuffer是Java系统提供的用于字节缓冲区之用的一个基于堆外内存实现的数据结构。在NIO中,无论是读取数据还是写入数据都需要经过ByteBuffer缓冲区做一次中转。


1 . ByteBuffer 的创建方式

ByteBuffer.allocate(1024);
new HeapByteBuffer(capacity, capacity);
ByteBuffer.allocateDirect(1024);
new DirectByteBuffer(capacity);

2 . ByteBuffer 的工作原理?
ByteBuffer 内部是采用一个字节数组来保存读与写的数据的,另外还有其他四个重要的指针参数,

mark <= position <= limit <= capacity

private int mark = -1; //一个标志量,可以暂存我们的读进度(读-写-读)
private int position = 0; //当前正读到或者写到的位置,会随着读写操作而自增
private int limit; //数据装载到的位置,读与写都不能超过此下标
private int capacity; //缓存区的容量

先看一个,先写入数据再读取的过程,
这里写图片描述
调用flip方法后,我们就结束了写模式,转为读模式,position被置为0,从第一个字符开始读取。
会发现这种切换太不灵活,必须读完或者写完才能进行对立的操作,因此这里就需要mark上场了,它可以暂存我们读的位置,然后再进行几步操作,a,获取到limit把position置为limit的值,b,再把limit置为capacity的值,此时可以继续往里面写入一定的数据,最后再通过 reset 把房子mark里的值赋给position,继续进行读操作。

相关扩展
|. 使用堆外内存有哪些好处呢?
理论上能减少GC暂停时间,使用对象池也具有这样的好处。
可以扩展至更大的内存空间。比如超过1TB甚至比主存还大的空间。
可以在进程间共享,减少JVM间的对象复制,使得JVM的分割部署更容易实现。
它的持久化存储可以支持快速重启,同时还能够在测试环境中重现生产数据。
站在系统设计的角度来看,使用堆外内存可以为你的设计提供更多可能。最重要的提升并不在于性能,而是决定性的。

||. 关于应用程序使用堆内内存的工作流程
这里写图片描述
首先,数据会加载到内核缓冲区,也就是第1步
然后又会将内容从内核缓冲区拷贝到用户态的缓冲区,也就是java这里的堆内存了,第2步
我们java调用send,发送的时候,再拷贝到内核缓冲区,第3步
最后再写入目标缓冲,比如网卡,第4步

read() 引入了一次从user mode到kernel mode的上下文切换。实际上调用了sys_read() 来从文件中读取data。第一次copy由DMA完成,将文件内容从disk读出,存储在kernel的buffer中。
然后data被copy到user buffer中,此时read()成功返回。这是触发了第二次context switch: 从kernel到user。至此,数据存储在user的buffer中。
send() socket call 带来了第三次context switch,这次是从user mode到kernel mode。同时,也发生了第三次copy:把data放到了kernel adress space中。当然,这次的kernel buffer和第一步的buffer是不同的两个buffer。
最终 send() system call 返回了,同时也造成了第四次context switch。同时第四次copy发生,DMA将data从kernel buffer拷贝到protocol engine中。第四次copy是独立而且异步的。

如果直接操作JVM的堆外内存,就可以省略掉2,3步,效率高哈

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:63555次
    • 积分:1112
    • 等级:
    • 排名:千里之外
    • 原创:51篇
    • 转载:0篇
    • 译文:1篇
    • 评论:7条
    Paradise
    文章分类
    最新评论