简介

妖魔鬼怪快快显形,今天F师兄帮助小师妹来斩妖除魔啦,什么BufferB,BufferL,BufferRB,BufferRL,BufferS,BufferU,BufferRS,BufferRU统统给你剖析个清清楚楚明明白白。

Buffer的分类

小师妹:F师兄不都说JDK源码是最好的java老师吗?为程不识源码,就称牛人也枉然。但是我最近在学习NIO的时候竟然发现有些Buffer类居然没有注释,就那么突兀的写在哪里,让人好生心烦。

更多内容请访问www.flydean.com

居然还有这样的事情?快带F师兄去看看。

小师妹:F师兄你看,以ShortBuffer为例,它的子类怎么后面都带一些奇奇怪怪的字符:

什么什么BufferB,BufferL,BufferRB,BufferRL,BufferS,BufferU,BufferRS,BufferRU都来了,点进去看他们的源码也没有说明这些类到底是做什么的。

还真有这种事情,给我一个小时,让我仔细研究研究。

一个小时后,小师妹,经过我一个小时的辛苦勘察,结果发现,确实没有官方文档介绍这几个类到底是什么含义,但是师兄我掐指一算,好像发现了这些类之间的小秘密,且听为兄娓娓道来。

之前的文章,我们讲到Buffer根据类型可以分为ShortBuffer,LongBuffer,DoubleBuffer等等。

但是根据本质和使用习惯,我们又可以分为三类,分别是:ByteBufferAsXXXBuffer,DirectXXXBuffer和HeapXXXBuffer。

ByteBufferAsXXXBuffer主要将ByteBuffer转换成为特定类型的Buffer,比如CharBuffer,IntBuffer等等。

而DirectXXXBuffer则是和虚拟内存映射打交道的Buffer。

最后HeapXXXBuffer是在堆空间上面创建的Buffer。

Big Endian 和 Little Endian

小师妹,F师兄,你刚刚讲的都不重要,我就想知道类后面的B,L,R,S,U是做什么的。

好吧,在给你讲解这些内容之前,师兄我给你讲一个故事。

话说在明末浙江才女吴绛雪写过一首诗:《春 景 诗》

莺啼岸柳弄春晴,

柳弄春晴夜月明。

明月夜晴春弄柳,

晴春弄柳岸啼莺。

小师妹,可有看出什么特异之处?最好是多读几遍,读出声来。

小师妹:哇,F师兄,这首诗从头到尾和从尾到头读起来是一样的呀,又对称又有意境!

不错,这就是中文的魅力啦,根据读的方式不同,得出的结果也不同,其实在计算机世界也存在这样的问题。

我们知道在java中底层的最小存储单元是Byte,一个Byte是8bits,用16进制表示就是Ox00-OxFF。

java中除了byte,boolean是占一个字节以外,好像其他的类型都会占用多个字节。

如果以int来举例,int占用4个字节,其范围是从Ox00000000-OxFFFFFFFF,假如我们有一个int=Ox12345678,存到内存地址里面就有这样两种方式。

第一种Big Endian将高位的字节存储在起始地址

第二种Little Endian将地位的字节存储在起始地址

其实Big Endian更加符合人类的读写习惯,而Little Endian更加符合机器的读写习惯。

目前主流的两大CPU阵营中,PowerPC系列采用big endian方式存储数据,而x86系列则采用little endian方式存储数据。

如果不同的CPU架构直接进行通信,就由可能因为读取顺序的不同而产生问题。

java的设计初衷就是一次编写处处运行,所以自然也做了设计。

所以BufferB表示的是Big Endian的buffer,BufferL表示的是Little endian的Buffer。

而BufferRB,BufferRL表示的是两种只读Buffer。

aligned内存对齐

小师妹:F师兄,那这几个又是做什么用的呢? BufferS,BufferU,BufferRS,BufferRU。

在讲解这几个类之前,我们先要回顾一下JVM中对象的存储方式。

还记得我们是怎么使用JOL来分析JVM的信息的吗?代码非常非常简单:

log.info("{}", VM.current().details());

输出结果:

# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# WARNING | Compressed references base/shifts are guessed by the experiment!
# WARNING | Therefore, computed addresses are just guesses, and ARE NOT RELIABLE.
# WARNING | Make sure to attach Serviceability Agent to get the reliable addresses.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

上面的输出中,我们可以看到:Objects are 8 bytes aligned,这意味着所有的对象分配的字节都是8的整数倍。

再注意上面输出的一个关键字aligned,确认过眼神,是对的那个人。

aligned对齐的意思,表示JVM中的对象都是以8字节对齐的,如果对象本身占用的空间不足8字节或者不是8字节的倍数,则补齐。

还是用JOL来分析String对象:

[main] INFO com.flydean.JolUsage - java.lang.String object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 12 (object header) N/A
12 4 byte[] String.value N/A
16 4 int String.hash N/A
20 1 byte String.coder N/A
21 1 boolean String.hashIsZero N/A
22 2 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total

可以看到一个String对象占用24字节,但是真正有意义的是22字节,有两个2字节是补齐用的。

对齐的好处显而易见,就是CPU在读取数据的时候更加方便和快捷,因为CPU设定是一次读取多少字节来的,如果你存储是没有对齐的,则CPU读取起来效率会比较低。

现在可以回答部分问题:BufferU表示是unaligned,BufferRU表示是只读的unaligned。

小师妹:那BufferS和BufferRS呢?

这个问题其实还是很难回答的,但是经过师兄我的不断研究和探索,终于找到了答案:

先看下DirectShortBufferRU和DirectShortBufferRS的区别,两者的区别在两个地方,先看第一个Order:

DirectShortBufferRU:

public ByteOrder order() {
return ((ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN)
? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
}
DirectShortBufferRS:

public ByteOrder order() {
return ((ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
}

可以看到DirectShortBufferRU的Order是跟nativeOrder是一致的。而DirectShortBufferRS的Order跟nativeOrder是相反的。

为什么相反?再看两者get方法的不同:

DirectShortBufferU:

public short get() {
try {
checkSegment();
return ((UNSAFE.getShort(ix(nextGetIndex()))));
} finally {
Reference.reachabilityFence(this);
}
}
DirectShortBufferS:

public short get() {
try {
checkSegment();
return (Bits.swap(UNSAFE.getShort(ix(nextGetIndex()))));
} finally {
Reference.reachabilityFence(this);
}
}

区别出来了,DirectShortBufferS在返回的时候做了一个bits的swap操作。

所以BufferS表示的是swap过后的Buffer,和BufferRS表示的是只读的swap过后的Buffer。

总结

不写注释实在是害死人啊!尤其是JDK自己也不写注释的情况下!

更多精彩内容且看:

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/java-io-nio-kinds-of-buffer/

本文来源:flydean的博客

欢迎关注我的公众号:程序那些事,更多精彩等着您!

小师妹学JavaIO之:NIO中那些奇怪的Buffer的更多相关文章

  1. 小师妹学JavaIO之:NIO中Channel的妙用

    目录 简介 Channel的分类 FileChannel Selector和Channel DatagramChannel SocketChannel ServerSocketChannel Asyn ...

  2. 小师妹学JavaIO之:文件系统和WatchService

    目录 简介 监控的痛点 WatchService和文件系统 WatchSerice的使用和实现本质 总结 简介 小师妹这次遇到了监控文件变化的问题,F师兄给小师妹介绍了JDK7 nio中引入的Watc ...

  3. 小师妹学JavaIO之:用Selector来发好人卡

    目录 简介 Selector介绍 创建Selector 注册Selector到Channel中 SelectionKey selector 和 SelectionKey 总的例子 总结 简介 NIO有 ...

  4. 小师妹学JavaIO之:Buffer和Buff

    目录 简介 Buffer是什么 Buffer进阶 创建Buffer Direct VS non-Direct Buffer的日常操作 向Buffer写数据 从Buffer读数据 rewind Buff ...

  5. 小师妹学JavaIO之:MappedByteBuffer多大的文件我都装得下

    目录 简介 虚拟地址空间 详解MappedByteBuffer MapMode MappedByteBuffer的最大值 MappedByteBuffer的使用 MappedByteBuffer要注意 ...

  6. 小师妹学JVM之:JIT中的PrintAssembly

    目录 简介 使用PrintAssembly 输出过滤 总结 简介 想不想了解JVM最最底层的运行机制?想不想从本质上理解java代码的执行过程?想不想对你的代码进行进一步的优化和性能提升? 如果你的回 ...

  7. 小师妹学JavaIO之:目录还是文件

    目录 简介 linux中的文件和目录 目录的基本操作 目录的进阶操作 目录的腰疼操作 总结 简介 目录和文件傻傻分不清楚,目录和文件的本质到底是什么?在java中怎么操纵目录,怎么遍历目录.本文F师兄 ...

  8. 小师妹学JavaIO之:文件File和路径Path

    简介 文件和路径有什么关系?文件和路径又隐藏了什么秘密?在文件系统的管理下,创建路径的方式又有哪些?今天F师兄带小师妹再给大家来一场精彩的表演. 文件和路径 小师妹:F师兄我有一个问题,java中的文 ...

  9. 小师妹学JVM之:JDK14中JVM的性能优化

    目录 简介 String压缩 分层编译(Tiered Compilation) Code Cache分层 新的JIT编译器Graal 前置编译 压缩对象指针 Zero-Based 压缩指针 Escap ...

随机推荐

  1. Postgres的索引01

    一.PG 9.3有以下索引类型 1.b-tree 1.1支持前导模糊查询,如xxx%或者^'xxx' 1.2忽略大小写字符前导模糊查询,如ILIKE 'XXX%'或者~*'^xxx' 1.3支持常见的 ...

  2. Spring Bean 定义

    Bean 定义 被称作 bean 的对象是构成应用程序的支柱.也是由 Spring IoC 容器管理的. bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象. 这些 bea ...

  3. windows 10 2016 企业版 长期服务 激活方式

    试了很多,失败. 使用这个ok———————————————————————————————— 使用方式: 2.1.下载AAct.exe  https://www.baidu.com/link?url ...

  4. Istio VirtualService 虚拟服务

    概念及示例 VirtualService 描述了一个或多个用户可寻址目标到网格内实际工作负载之间的映射 . 虚拟服务让您配置如何在服务网格内将请求路由到服务,这基于 Istio 和平台提供的基本的连通 ...

  5. 谈谈MySQL 索引

    1.索引是什么 索引(Index)是帮助MySQL高效获取数据的数据结构.我们可以简单理解为:索引的目的在于提高查询效率. 2.原理 索引的数据结构是B+树,原理图如下 关于B+树的详细介绍,可以参见 ...

  6. Java——异常处理,数据库连接

    在学习数据库连接时看到try(){}结构,查了一下写在这里: import java.sql.Connection; import java.sql.DriverManager; import jav ...

  7. vue使用IntersectionObserver实现无限下拉信息流

    基于 IntersectionObserver 异步监听方法,实现无线信息流下拉加载, https://developer.mozilla.org/zh-CN/docs/Web/API/Interse ...

  8. MySQL常用控制台指令

    MySQL服务的启用与停止 MySQL服务的启用: net start mysql80 MySQL服务的停止: net stop mysql80 MySQL的登入与退出 数据库的登入: mysql - ...

  9. Robot Framework(15)- 扩展关键字

    如果你还想从头学起Robot Framework,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1770899.html 前言 什么是扩展 ...

  10. PowerPC-Link Command File解析

    https://mp.weixin.qq.com/s/CATWma2mv5IPYGtKZLuGDA   以Code Warrior 11生成的flash版本(FLASH.lcf)为例   一. 参考资 ...