Java NIO study notes a

Buffer Operations

Process perform I / O operations, boils down to ask the operating system, it is either the cache data area drained embodiment (writing), or data area fill data (read). Process uses this mechanism to handle all the data in and out of operation.
m7IfQH.png
Process uses read () system call, which requires the buffer is filled. Kernel then issues a command to the disk controller, which requires reading data from the disk. When data is written to disk kernel memory directly through the DMA buffer technology, disk controller once the buffer is full, immediate memory from kernel space data in the buffer is copied to the process you perform read () call specified buffer.

Scatter / gather

According to the concept of divergence / convergence, the process requires only a system call, you will be able to pass a series of buffer addresses to the operating system. Then, the core can be filled sequentially or more buffers drained, when the read data to a plurality of diverging user-space buffer, re-writing of the data from the plurality of buffers coming together.
m7oYnA.png

The use of virtual memory to avoid some copies

The aforementioned storage device controller DMA can not be used directly to user space need to be copied from the kernel space to user space. However, the use of multiple memory mapping techniques to avoid this copy.
Modern operating systems use virtual memory, it has great advantages:

  1. Multiple virtual addresses can be mapped to the same physical address.
  2. Virtual memory space may be greater than the actual hardware memory available. By the characteristics of virtual memory, virtual address mapping buffer space and user space kernel buffer virtual address to a physical address (i.e., multiple memory mapping techniques). But it is also a prerequisite, the user and kernel buffer must be aligned with the same page, the size of the buffer must also be a disk control multiple of block size.

    m7T9ud.png

Paging using an operating system to perform IO operations

  1. Determines that the requested data distributed file system in which pages, these pages are not necessarily sequential
  2. Allocate enough space in the kernel page types to accommodate page file system
  3. Establish a mapping between the file system memory pages and pages on disk
  4. Generates a page fault anomaly for each page
  5. The virtual memory system to capture abnormal missing page, call the appropriate page fault handler will be transferred to the main memory page file system
  6. After successfully transferred to the page, the file system team parse the raw data to obtain the file contents and attribute information.

File systems and also other memory page as the page is cached in the main memory z

Memory-Mapped Files

m7sbJ1.png
内存映射IO使用文件系统建立用户空间直到可用文件系统页的虚拟内存映射。
当用户进行触碰到映射内存空间时,会自动产生页错误,从而将文件系统从磁盘读进主存。如果用户修改了映射内存空间时,相应的页会被标记为脏页,随后就会将更改持久化到磁盘。

其优点:

  1. 用户进程直接将文件数据当作内存。
  2. 自动产生页错误,将文件数据从磁盘读入主存
  3. 操作系统的虚拟内存子系统可以对这些页进行智能高速缓存
  4. 数据总是按页对齐的
  5. 大型文件使用映射可以节约内存。

文件锁定机制

文件锁定机制允许一个进程阻止其它仅从存取某文件,或限制其存取方式。
文件锁定的锁定区域可以是整个文件也可ui细致到单个字节。

共享锁和独占锁

多个共享锁可以同时对同一文件区域发生作用;独占锁要求相关区域不能有其它锁定在起作用。

共享锁和独占锁的经典应用 --- 控制读取共享文件的更新
某个进程要读取文件,就要先取得相关区域的共享锁。其它希望读取相同文件区域的进程也会请求共享锁。多个进程得以并行读取,互不影响。如果在此时有其它进行想要更新文件,那么它需要请求独占锁,然后该进行会进入阻滞状态,直到既有锁定(共享的,独占的)全部解除它才能拿到独占锁。一旦该进程拿到了独占锁,其它所有的共享锁读取线程间进入阻滞状态,直到独占锁解除。

流I/O

并非所有的I/O都是面向块的,也有流I/O,其原理模仿了通道。I/O流字节必须顺序读取。流的传输一般比块设备慢,进程用于间歇性输入。

Buffer类

一个Buffer对象是固定容量的数据的容器。在这里数据可以被存储并在之后用于检索。

Buffer类的层次图

m7bFER.png

属性

    private int mark = -1;
    private int position = 0;
    private int limit;
    private int capacity; 
  1. 容量(capacity)
  2. 上界(limit)
    缓冲区第一个不能被读或写的元素。或者说是现存元素的计数。其指明了缓冲区中有效内容末端的位置。
  3. 标记(mark)
    一个备忘的位置。使用mark()来设定mark=postion.调用reset()设定position=mark
    这四个属性之间遵循的关系为:
    0<= mark <= position <= limit <= capacity

重要方法

put()

put方法就是将元素加入缓冲区,值得注意的是,put方法只改变position,不会改变limit和capacity。
mHPgtU.png

flip()

    public final Buffer flip() {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }

filp()方法将一个能够继续添加数据的填充状态的缓冲区翻转为一个准备读出元素的释放状态。根据代码filp()所作的工作不言而喻。

rewind()

rewind方法和flip方法非常类似,但是它不会影响上界属性,可以利用rewind方法来重新读已经被翻转的缓冲区中的数据。

hasRemaining()

        //切换到读模式
        buffer.flip();
        int count=buffer.remaining();
        System.out.println("当前位置距离上界还有:"+count);
        
        while (buffer.hasRemaining()){
            System.out.print(buffer.get()+" ");
        }

hasRemaining()可以判断当前位置是否已经达到buffer的上界。remaining()可以获取当前位置与上界的距离。

compact()

当需要从buffer中释放一部分已经被读取过的数据时,可以使用compact方法,他会将为读的数据元素下移动使得第一个元素的索引为0.该方法在复制数据的场景下,比使用get方法和put方法更加的高效。

关于标记的一些注意点

在未设置标记之前,mark是等于-1的。此时如果调用reset()会抛出InvalidMarkExceptioin异常。值得注意的是由许多方法都是会将mark重置为-1的。如:rewind(),flip(),clear()等。

缓冲区相等

两个缓冲区相等的条件:

  1. 对象类型相同
  2. 两个对象剩余同样的元素(剩余是指position到limit之间的元素)

被认为相等的两个缓冲区
mbGwtO.png

批量的移动

以CharBuffer为例子

public CharBuffer get(char[] dst)
//offset参数是填充dst的起点位置
public CharBuffer get(char[] dst,int offset,int lenth);

public final CharBuffer put(char[] src)
public CharBuffer put(char[] src,int offset,int length)
public CharBUffer put(CharBuffer src)

可以使用以下方法高效的读取处理数据

    buffer.flip();
    int[] arr=new int[10];
    while (buffer.hasRemaining()){
        int len=Math.min(arr.length,buffer.remaining());
        buffer.get(arr,0,len);
        //处理数据
        processData(arr,len);
    }

缓存区创建的两个关键方法

public static CharBuffer allocate(int capacity)

public static CharBuffer Wrap(char[] array)
//offset参数用来初始化position参数,length参数用来初始化limit参数
public static CharBuffer wrap(char[] array,int offset,int length)

Create a new cache area in two ways, namely, distribution or packaging operations.
Methods allocate allocation way, he will classify an array to store data. The method is to wrap an array package as a buffer. This means that any changes to this array will be visible to the buffer.

Copy buffer

public abstract CharBuffer duplicate();
public abstract CharBuffer asReadOnlyBuffer();
public abstract CharBuffer slice();

Use methods to create a duplicate of the original and a copy of the shared buffer buffer data elements. They shared data elements but has its own position, the upper and tag attributes.

Use asReadOnlyBuffer method to create a read-only copy of the buffer. It creates a copy is not allowed to use the put method.

Use slice method to create a copy of a position to the limit of the elements.

It is noted that the above three methods are not used to store data in the heap reallocate space. So they are all methods of copy buffer.

Byte buffer

Byte order

Big-endian byte order is divided into small end storage memory and
big-endian:
high stored memory address bits lower
small end:
low address bits stored in the lower memory

Using ByteOrder order()methods available byte order of the buffer; using ByteBuffer order(ByteOrder bo)methods may be modified buffer byte order.

Direct buffers

A major feature byte buffer is that it can be directly buffer. It could be I / O source or destination channel performed.

Non-direct buffers: non-direct buffers will be established in the buffer memory in the JVM.
mO5GXF.png

Non-direct buffers: Buffer directly established in physical memory, can improve efficiency.
mO5N79.png

        //分配直接缓冲区
        ByteBuffer bf=ByteBuffer.allocateDirect(10);
        //判断其是否是直接缓冲区,结果是true
        System.out.println(bf.isDirect());

A view buffer

ByteBuffer class allows the view to create the data mapping byte type buffer byte other bits of the original data type. View object maintains its own capacity, location, and marks the upper bound, but the original buffer and shared data elements.

        ByteBuffer bf=ByteBuffer.allocate(10);
        IntBuffer intBuffer=bf.asIntBuffer();

Guess you like

Origin www.cnblogs.com/zofun/p/11442982.html
Recommended