博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《JAVA NIO》第一章 简介
阅读量:5060 次
发布时间:2019-06-12

本文共 2517 字,大约阅读时间需要 8 分钟。

1.2 CPU已不再是束缚

相反,是JVM 自身在I/O 方面效率欠佳。操作系统与Java 基于流的I/O模型有些不匹配。

操作系统要移动的是大块数据(缓冲区),这往往是在硬件直接存储器存取(DMA)的协助下完成的。而JVM 的I/O 类喜欢操作小块数据——单个字节、几行文本。

结果,操作系统送来整缓冲区的数据,java.io 的流数据类再花大量时间把它们拆成小块,往往拷贝一个小块就要往返于几层对象。操作系统喜欢整卡车地运来数据,java.io 类则喜欢一铲子一铲子地加工数据。有了NIO,就可以轻松地把一卡车数据备份到您能直接使用的地方(ByteBuffer 对象)。

1.4.1缓冲区操作

调用read的过程:

         进程使用read( )系统调用,要求其缓冲区被填满。

         内核随即向磁盘控制硬件发出命令,要求其从磁盘读取数据。

         磁盘控制器把数据直接写入内核内存缓冲区,这一步通过DMA 完成,无需主CPU 协助。

         一旦磁盘控制器把缓冲区装满,内核即把数据从内核空间的临时缓冲区拷贝到进程执行read( )调用时指定的缓冲区。

用户空间是非特权区域:     

          比如,在该区域执行的代码就不能直接访问硬件设备。内核空间是操作系统所在区域。内核代码有特别的权力:它能与设备控制器通讯,控制着用户区域进程的运行状态,等等。最重要的是,所有I/O 都直接(如这里所述)或间接(见1.4.2 小节)通过内核空

          间。

为什么不让IO设备直接把数据copy到用户空间:

      1、硬件通常不能直接访问用户空间(硬件设备通常不能直接使用虚拟内存地址)

      2、像磁盘这样基于块存储的硬件设备操作的是固定大小的数据块,而用户进程请求的可能是任意大小的或非对齐的数据块。在数据往来于用户空间与存储设备的过程中,内核负责数据的分解、再组合工作,因此充当着中间人的角色。

内核缓冲:

     内核试图对数据进行高速缓存或预读取,因此进程所需数据可能已经在内核空间里了。如果是这样,该数据只需简单地拷贝出来即可。如果数据不在内核空间,则进程被挂起,内核着手把数据读进内存。

 1.4.2虚拟内存

   优点:

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

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

   内存空间多重映射:     

             把内核空间地址与用户空间的虚拟地址映射到同一个物理地址,这样,DMA 硬件(只能访问物理内存地址)就可以填充对内核与用户空间进程同时可见的缓冲区。           

              这样就省去了内核与用户空间的往来拷贝,但前?条件是,内核与用户缓冲区必须使用相同的页对齐,缓冲区的大小还必须是磁盘控制器块大小(通常为512 字节磁盘扇区)的倍数。

 

 1.4.3 内存页面调度(缺页中断和调入)

       把内存页大小设定为磁盘块大小的倍数,这样内核就可直接向磁盘控制硬件发布命令,把内存页写入磁盘,在需要时再重新装入。结果是,所有磁盘I/O 都在页层面完成。

       对于采用分页技术的现代操作系统而言,这也是数据在磁盘与物理内存之间往来的唯一方式。

1.4.4文件IO

      1、老式的操作系统往往直接向磁盘驱动器发布命令,要求其读取所需磁盘扇区。而采用分页技术的现代操作系统则利用请求页面调度取得所需数据。

      2、采用分页技术的操作系统执行I/O 的全过程:

            •确定请求的数据分布在文件系统的哪些页(磁盘扇区组)。磁盘上的文件内容和元数据可能跨越多个文件系统页,而且这些页可能也不连续。

           • 在内核空间分配足够数量的内存页,以容纳得到确定的文件系统页。

           • 在内存页与磁盘上的文件系统页之间建立映射。

           • 为每一个内存页产生页错误。

           • 虚拟内存系统俘获页错误,安排页面调入,从磁盘上读取页内容,使页有效。

           • 一旦页面调入操作完成,文件系统即对原始数据进行解析,取得所需文件内容或属性信息。

     3、这些文件系统数据也会同其他内存页一样得到高速缓存。对于随后发生的I/O请求,文件数据的部分或全部可能仍旧位于物理内存当中,无需再从磁盘读取即可重复使用。

     4、大多数操作系统假设进程会继续读取文件剩余部分,因而会预读额外的文件系统页。如果内存争用情况不严重,这些文件系统页可能在相当长的时间内继续有效。这样的话,当稍后该文件又被相同或不同的进程再次打开,可能根本无需访问磁盘。这种情况您可也            碰到过:当重复执行类似的操作,如在几个文件中进行字符串检索,第二遍运行得似乎快多了。

     5、文件内容的改变(通过write( ))将导致文件系统页变脏,随后通过页面调出,与磁盘上的文件内容保持同步。

     6、文件的创建方式是,先把文件映射到空闲文件系统页,在随后的写操作中,再将文件系统页刷新到磁盘。

1.4.4.1内存映射文件

    本质是内存多重映射

     

   优点:

• 用户进程把文件数据当作内存,所以无需发布read( )或write( )系统调用。(如果没有缺页中断的话,应该不会经历内核空间)

• 当用户进程碰触到映射内存空间,页错误会自动产生,从而将文件数据从磁盘读进内存。如果用户修改了映射内存空间,相关页会自动标记为脏,随后刷新到磁盘,文件得到更新。

• 操作系统的虚拟内存子系统会对页进行智能高速缓存,自动根据系统负载进行内存管理。

• 数据总是按页对齐的,无需执行缓冲区拷贝。

• 大型文件使用映射,无需耗费大量内存,即可进行数据拷贝。

1.4.4.2 文件锁定

“文件锁定”从字面上看有锁定整个文件的意思(通常的确是那样),但锁定往往可以发生在更为细微的层面,锁定区域往往可以细致到单个字节。锁定与特定文件相关,开始于文件的某个特定字节地址,包含特定数量的连续字节。这对于协调多个进程互不影响地访问文件不同区域,是至关重要的。

文件锁定有两种方式:共享的和独占的。

1.4.5 流IO

I/O 字节流必须顺序存取,常见的例子有TTY(控制台)设备、打印机端口和网络连接。

就绪性选择:操作系统受命查看一系列流,并提醒进程哪些流已经就绪。这样,仅仅凭借操作系统返回的就绪信息,进程就可以使用相同代码和单一线程,实现多活动流的多路传输。

转载于:https://www.cnblogs.com/YDDMAX/p/5647326.html

你可能感兴趣的文章
Shell脚本大量示例
查看>>
C# 申请非托管内存
查看>>
Android内存泄露自动检测神器LeakCanary
查看>>
python-9:基础点滴 字符串函数之二 str
查看>>
红黑树
查看>>
Java爬虫搜索原理实现
查看>>
Python中,如何初始化不同的变量类型为空值
查看>>
volatile
查看>>
javascript性能优化总结二(转载)
查看>>
软件工程个人作业04-四则运算网页版
查看>>
栈和队列的方法
查看>>
GC模式
查看>>
JavaMail与Spring整合
查看>>
The user specified as a definer ('root'@'%') does not exist 解决方法 权限问题
查看>>
IDEA
查看>>
java基础知识起步
查看>>
Python学习笔记
查看>>
python笔记
查看>>
构建之法--探索篇(二)
查看>>
浅析软件开发的3个层次
查看>>