JavaのNIOの研究ノート

バッファ操作

プロセスがI / O操作を実行、それは(読み取り)データを埋めるキャッシュデータ領域排水の実施形態(書き込み)、またはデータ領域のいずれかで、オペレーティングシステムを尋ねるために沸きます。プロセスは、操作の内と外のすべてのデータを処理するために、このメカニズムを使用しています。
m7IfQH.png
プロセスは、バッファが満たされている必要リード()システムコールを使用します。カーネルは、ディスクからの読み出しデータを必要とするディスクコントローラにコマンドを発行します。データはディスクコントローラ、直接DMAバッファ技術によりディスクのカーネルメモリに書き込まれると、バッファがいっぱいになると、バッファ内のカーネル空間データからの即時メモリは、あなたが(読み実行プロセスにコピーされます)指定されたコールバッファ。

スキャッタ/ギャザー

発散/収束の概念によると、プロセスは唯一のシステムコールを必要とし、あなたは、オペレーティングシステムにバッファ一連のアドレスを渡すことができるようになります。次いで、コアは、連続的または排出以上のバッファを充填することができるときに一緒に来て複数のバッファからのデータのユーザ空間バッファ、再書き込みを発散する複数の読み出しデータ。
m7oYnA.png

いくつかのコピーを避けるために、仮想メモリの使用

DMAは、ユーザ空間に直接使用することができない、前述の記憶デバイス制御装置は、ユーザ空間にカーネル空間からコピーする必要があります。しかし、このコピーを回避するために、複数のメモリマッピング技術の使用。
現代のオペレーティングシステムは、仮想メモリを使用し、それは大きな利点があります。

  1. 複数の仮想アドレスが同じ物理アドレスにマッピングすることができます。
  2. 仮想メモリ空間は、使用可能な実際のハードウェアメモリよりも大きくすることができます。仮想メモリの特性によって、仮想アドレスマッピングバッファ空間と物理アドレス(すなわち、複数のメモリマッピング技術)へのユーザ空間カーネルバッファの仮想アドレス。しかし、それはまた、前提条件であり、ユーザとカーネルバッファが同じページに整列しなければならない、バッファのサイズは、ブロックサイズのディスク制御倍数でなければなりません。

    m7T9ud.png

IO操作を実行するためにオペレーティングシステムを使用してページング

  1. 要求されたデータがどのページでファイルシステムを分散することを決定し、これらのページは必ずしもシーケンシャルではありません
  2. ページファイルシステムに対応するために、カーネルのページタイプに十分なスペースを割り当て
  3. ディスク上のファイル・システム・メモリ・ページとページの間のマッピングを確立します
  4. 各ページのページフォルト異常を生成します
  5. 異常な不足しているページをキャプチャするために、仮想メモリシステム、適切なページフォルトハンドラを呼び出すには、メインメモリのページファイルシステムに転送されます
  6. 成功したページに転送された後、ファイル・システム・チームは、ファイルの内容を取得するために、生データを解析し、属性情報。

ファイルシステムと、ページがメインメモリZにキャッシュされているように、他のメモリページ

メモリマップファイル

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)

二つの方法、すなわち、分布や包装作業中に新しいキャッシュ領域を作成します。
メソッドは、割り当て方法を割り当てる、彼は、データを格納する配列を分類します。この方法は、バッファとしてアレイパッケージをラップすることです。これは、この配列への変更がバッファに見えるであろうことを意味します。

コピーバッファ

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

オリジナルの複製と共有バッファバッファのデータ要素のコピーを作成するためのメソッドを使用します。彼らは、データ要素を共有しますが、自身の位置、上限およびタグ属性があります。

バッファの読み取り専用コピーを作成するために、asReadOnlyBufferメソッドを使用します。それはコピーがputメソッドを使用することを許可されていません作成します。

要素の限界まで位置のコピーを作成するために、スライスメソッドを使用します。

なお、上記3つの方法がヒープREALLOCATE空間にデータを格納するために使用されていないことに留意されたいです。そこで彼らは、コピーバッファのすべてのメソッドです。

バイトバッファ

バイト順

ビッグエンディアンバイト順は、小端記憶メモリとに分割されている
ビッグエンディアン:
高格納されているメモリアドレスビット下位
小端を:
低いメモリに格納された下位アドレスビットを

使用ByteOrder order()方法使用可能なバイトバッファの順序、使用ByteBuffer order(ByteOrder bo)方法は、バッファのバイト順序を変更してもよいです。

直接バッファ

大きな特徴のバイトのバッファは、それが直接バッファリングすることができるということです。これは、I / Oソースまたはデスティネーションチャンネルに行うことができます。

非ダイレクトバッファ:非ダイレクトバッファは、JVM内のバッファメモリに確立されます。
mO5GXF.png

非ダイレクトバッファ:バッファ直接物理メモリに設立さは、効率を向上させることができます。
mO5N79.png

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

ビューバッファ

ByteBufferのクラスでは、ビューは、元のデータ・タイプのデータ・マッピング・バイト型バッファバイト他のビットを作成することを可能にします。ビューオブジェクトは、それ自身の容量、位置を維持し、上限をマークするが、元のバッファと共有データ・エレメント。

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

おすすめ

転載: www.cnblogs.com/zofun/p/11442982.html