JAVA NIO Buffer
所谓的输入,输出,就是把数据移除或移入缓冲区。
硬件不能直接访问用户控件(JVM)。
基于存储的硬件设备操控的是固定大小的数据块儿,用户请求的是任意大小的或非对齐的数据块儿。
虚拟内存:使用虚拟地址取代取代物理地址。
-
可以有多个虚拟地址指向同一个物理地址。
-
虚拟内存空间可以大于实际的硬件内存。
应用:直接内存使用--使用户空间虚拟地址和内核虚拟地址同时指向同一个物理地址,可以使硬件直接访问用户空间内存。
数据库等应用严重依赖文件锁定。
缓冲区:
缓冲区是包在一个对象内的基本数据类型数组。Buffer把关于数据内容和信息包含在一个对象中,并定义了一系列API。
信息提供操作属性:0<=mark<=position<=limit<=capicity
-
容量(Capicity):创建时设定,无法动态更改。
-
上界(Limit):现存元素计数。
-
位置(Position):下一个要被读取的元素位置。动态更新。
-
标记(Mark):备忘位置,mark()设定mark=position,reset()设定postion=mark。
插入“hello”之后:
Buffer类方法签名:
返回Buffer自身的一些方法可以直接级联调用。
创建只读缓存。例如ByteBuffer:
ByteBuffer bf = ByteBuffer.allocate(1024).asReadOnlyBuffer()
Flip():讲一个能够继续添加数据元素的填充状态的缓冲区翻转为一个准备读出元素的释放状态。
bf.flip() = bf.limit(bf.position()).position(0)
rewind():
bf.rewind() = bf.position(0)
缓冲区不是线程安全。
mark():Buffer是从当前位置开始向通道内输出内容的,如下,怎会输出‘ow’,position到6
reset()后,positon至mark位置。
两个具有相同元素的Buffer,只要剩余元素数量(从位置到上界)相同,就equals=true。
Buffer.get(byte[]):BufferUnderflowException;
当将一个buffer内容读入数组,buffer内容不足以填充数组时,会抛出此异常。因为需要指明可以读入的buffer内容长度。如下:
Buffer.get(byte[], 0, Buffer.remaining());
Buffer.put(byte[]):BufferUnderflowException;
当将数组元素写入buffer,buffer没有足够的空间时,会抛出此异常。
Buffer.wrap(byte[], int offset, int length):offset,length只是设置了初始化状态,并不是创建只占数组子集的缓冲区,缓冲区可以可以存取数组的全部范围。区别slice函数。
allocate(), wrap() 创建的缓冲区都是间接的,使用备份数组,可以获得数组的操作权。
Duplicate()复制缓冲区会创建一个新的Buffer对象,但是并不复制数据,原始缓冲区和副本会操作同样的数据元素。
Slice() 创建从原始缓冲区当前位置开始的新的缓冲区,容量是原始缓冲区的剩余容量,(limit-position),与原始缓冲区共享一段数据元素子序列。分割出来的子序列继承只读和直接属性。
每个基本的数据类型都是以连续的字节序列存储在内存中,多字节被存储在内存中的方式称为字节顺序(endian-ness)。如果数字数值的最高字节--big-end(大端)位于低位地址,那么系统就是大端字节顺序,反之小端字节顺序。
IP协议规定了使用大端的网络字节顺序概念。
通过ByteOrder.nativeOrder() 输出LITTLE_ENDIAN或者BIG_ENDIAN判断。
Java默认的字节序是大端序,系统无关性,ByteBuffer.order() 总是范围ByteOrder.BIG_ENDIAN。
只有字节缓冲区有资格参与IO操作,IO操作的目标区域必须是连续的字节序列。JVM中的数据字节数组可能存储不连续,切GC可能会对其进行移动。所以IO不能直接操作。
直接缓冲区用于与通道或固有IO例程交互,通过固有代码告知系统直接操作内存区域。
直接缓冲区=》通道
非直接缓冲区=》临时直接缓冲区=》IO=》临时直接缓冲区回收。
选择依据执行频率,高频脚本使用直接缓存区。
创建直接缓冲区是调用本地操作系统分配的内存,比基于JVM创建的基于堆栈的缓冲区更加耗费,所以也不会被回收管理。
先使其工作,再加快其运行。首先注重正确性。过早的优化是所有祸害的根源。
ByteBuffer.allocateDirect(),开辟直接内存。
视图缓冲区:
通过已有的缓冲区对象示例的工厂方法来创建。视图缓冲维护自己的属性、容量、位置、上界和标记,但是和原来的缓冲区共享数据元素。如,ByteBuffer类允许创建视图来将byte型缓冲数组转化为其它的原始类型,ByteBuffer.asLongBuffer()。为基础缓冲区的切分,基于基础缓冲区的位置和上界(position-limit)
如下,ByteBuffer.asCharBuffer():
ByteBuffer中的两个字节映射成CharBuffer中的一个字符,CharBuffer中的字节排序不可以再改变。
数据元素视图:
以多字节数据形式存取byte数据组,存取和转化:
从ByteBuffer的当前位置存取字节数据,根据缓冲区当前的有效字节数序,字节会被排列或打乱成原始的数据类型。
例如getInt(),从当前位置开始的四个字节会被包装成一个Int返回。如下:
映射缓冲区(MappedByteBufefer):
通过内存映射存取元素的字节缓冲区,直接存取内存,只能通过FileChannel类创建。