NIO须要了解的一些概念

几个概念:

缓冲区(Buffers)

新的 Buffer 类是常规 Java 类和通道之间的纽带。原始数据元素组成的固定长度数组,封装在包含状态信息的对象中,存入缓冲区。缓冲区提供了一个会合点:通道既可提取放在缓冲区中的数 据(写),也可向缓冲区存入数据供读取(读)。此外,还有一种特殊类型的缓冲区,用于内存映射文件。

通道(Channels)

NIO 新引入的最重要的抽象是通道的概念。Channel 对象模拟了通讯链接,管道既能够是单向的(进或出),也能够是双向的(进和出)。能够把通道想象成链接缓冲区和 I/O 服务的捷径

文件锁定和内存映射文件(File locking and memory-mapped files)

新的 FileChannel 对象包含在 java.nio.channels 软件包内,提供许多面向文件的新特 性,其中最有趣的两个是文件锁定和内存映射文件。
在多个进程协同工做的状况下,要协调各个进程对共享数据的访问,文件锁定是必不可少的工具。

将文件映射到内存,这样在您看来,磁盘上的文件数据就像是在内存中同样。这利用了操做系统的虚拟内存功能,无需在内存中实际保留一份文件的拷贝,就可实现文件内容的动态高速缓存。

套接字(Sockets)

套 接字通道类为使用网络套接字实现交互提供了新方法。套接字通道可工做于非块模式,并可与选择器一同使用。所以,多个套接字可实现多路传输,管理效率也比 java.net 提供的传统套接字更高。三个新套接字通道,即 ServerSocketChannel、SocketChannel 和 DatagramChannel

选择器(Selectors)

选择器可实现就绪性选择。Selector 类提供了肯定一或多个通道当前状态的机制。使用选择 器,借助单一线程,就可对数量庞大的活动 I/O 通道实施监控和维护。

正则表达式(Regular expressions)

新增的 java.util.regex 软件包将相似 Perl 语言的正则表达式处理机制引入 Java。这一人 们期盼已久的特性有着普遍用途。

新的正则表达式 API 之因此被当作是 NIO 的组成部分,是因 JSR 51 把它与其余 NIO 特性放在一块儿做了详细说明。虽然它在许多方面与 NIO 的其余组成部分缺少平行关系,但它在文件处理等众多领域都是极其有用的。

字符集(Character sets)
java.nio.charsets 提供了新类用于处理字符与字节流之间的映射关系。您能够对字符转换映射方式进行选择,也能够本身建立映射。

磁盘I/O的示例

图中明显忽略了不少细节,仅显示了涉及到的基本步骤。

如图

注 意图中用户空间和内核空间的概念。用户空间是常规进程所在区域。JVM 就是常规进程,驻守于用户空间。用户空间是非特权区域:好比,在该区域执行的代码就不能直接访问硬件设备。内核空间是操做系统所在区域。内核代码有特别的 权力:它能与设备控制器通信,控制着用户区域进程的运行状态,等等。最重要的是,全部 I/O 都直接(如这里所述)或间接(见 1.4.2 小节)经过内核空间。

当进程请求 I/O 操做的时候,它执行一个系统调用(有时称为陷阱)将控制权移交给内核。C/C++程序员所熟知的底层函数 open( )、read( )、write( )和 close( )要作的无非就是创建和执行适当 的系统调用。当内核以这种方式被调用,它随即采起任何须要步骤,找到进程所需数据,并把数据传送到用户空间内的指定缓冲区。内核试图对数据进行高速缓存或 预读取,所以进程所需数据可能已经在内核空间里了。若是是这样,该数据只需简单地拷贝出来便可。若是数据不在内核空间,则进程被挂起,内核着手把数据读进 内存。

看了图 1-1,您可能会以为,把数据从内核空间拷贝到用户空间彷佛有些多余。为何不直接让磁盘控制器把数据送到用户空间的缓冲区呢?这样作有几个问题。首先, 硬件一般不能直接访问用户空间 1。其次,像磁盘这样基于块存储的硬件设备操做的是固定大小的数据块,而用户进程请求的多是任意大小的或非对齐的数据块。在数据往来于用户空间与存储设 备的过程当中,内核负责数据的分解、再组合工做,所以充当着中间人的角色。

发散/汇聚

许 多操做系统能把组装/分解过程进行得更加高效。根据发散/汇聚的概念,进程只需一个系统调用,就能把一连串缓冲区地址传递给操做系统。而后,内核就能够顺 序填充或排干多个缓冲区,读的时候就把数据发散到多个用户空间缓冲区,写的时候再从多个缓冲区把数据汇聚起来这样用户进程就没必要屡次执行系统调用(那样作 可能代价不菲),内核也能够优化数据的处理过程,由于它已掌握待传输数据的所有信息。若是系统配有多个 CPU,甚至能够同时填充或排干多个缓冲区。

虚拟内存

全部现代操做系统都使用虚拟内存。虚拟内存意为使用虚假(或虚拟)地址取代物理(硬件RAM)内存地址。这样作好处颇多,总结起来可分为两大类:

1. 一个以上的虚拟地址可指向同一个物理内存地址。

2. 虚拟内存空间可大于实际可用的硬件内存。

设备控制器不能经过 DMA 直接存储到用户空间,但经过利用上面提到的第一项,则能够达到相同效果。把内核空间地址与用户空间的虚拟地址映射到同一个物理地址,这样,DMA 硬件(只能访问物理内存地址)就能够填充对内核与用户空间进程同时可见的缓冲区

如图,进程虚拟内存和内核虚拟内存映射到的物理地址都同样,这样DMA写到实际的物理内存后,两个缓冲区指向的物理地址都同样,那么他们就同时能访问到数据了。

但 前提条件是,内核与用户缓冲区必须使用相同的页对齐,缓冲区的大小还必须是磁盘控制器块大小(一般为 512 字节磁盘扇区)的倍数。操做系统把内存地址空间划分为页,即固定大小的字节组。内存页的大小老是磁盘块大小的倍数,一般为 2 次幂(这样可简化寻址操做)。典型的内存页为 1,02四、2,048 和 4,096 字节。虚拟和物理内存页的大小老是相同的。

如上图显示了来自多个虚拟地址的虚拟内存页是如何映射到物理内。

内存页面调度

为 了支持虚拟内存的第二个特性(寻址空间大于物理内存),就必须进行虚拟内存分页(常常称为交换,虽然真正的交换是在进程层面完成,而非页层面)。依照该方 案,虚拟内存空间的页面可以继续存在于外部磁盘存储,这样就为物理内存中的其余虚拟页面腾出了空间。从本质上说,物理内存充当了分页区的高速缓存;而所谓 分页区,即从物理内存置换出来,转而存储于磁盘上的内存页面。java

相关文章
相关标签/搜索