最近在看 JAVA NIO 的相关知识,了解一下IO的底层实现原理。

IO涉及到的底层的概念大致如下:

1) 缓冲区操作。2) 内核空间与用户空间。3) 虚拟内存。4) 分页技术。

一,虚拟存储器

虚拟存储器是硬件异常(缺页异常)、硬件地址翻译、主存、磁盘文件和内核软件的完美交互,它为每个进程提供了一个大的、一致的和私有的地址空间。
虚拟存储器的三大能力:①将主存看成是一个存储在磁盘上的地址空间的高速缓存。②为每个进程提供了一个一致的地址空间。③保护每个进程的地址空间不被其他进程破坏。
虚拟内存的两大好处:① 一个以上的虚拟地址可指向同一个物理内存地址。② 虚拟内存空间可大于实际可用的硬件内存。

二,用户空间与内核空间
设虚拟地址为32位,那么虚拟地址空间的范围为0~4G。操作系统将这4G分为二部分,将最高的1G字节(虚拟地址范围为:0xC0000000-0xFFFFFFFF)供内核使用,称为内核空间。而将较低的3G字节供各个进程使用,称为用户空间。
每个进程可以通过系统调用进入内核,因为内核是由所有的进程共享的。对于每一个具体的进程,它看到的都是4G大小的虚拟地址空间,即相当于每个进程都拥有一个4G大小的虚拟地址空间。

三,IO操作
一般IO缓冲区操作:
1) 用户进程使用read()系统调用,要求其用户空间的缓冲区被填满。
2) 内核向磁盘控制器硬件发命令,要求从磁盘读入数据。
3) 磁盘控制器以DMA方式(数据不经过CPU)把数据复制到内核缓冲区。
4) 内核将数据从内核缓冲区复制到用户进程发起read()调用时指定的用户缓冲区。

从上图可以看出:磁盘中的数据是先读取到内核的缓冲区中。然后再从内核的缓冲区复制到用户的缓冲区。为什么会这样呢?
因为用户空间的进程是不能直接硬件的(操作磁盘控制器)。磁盘是基于块存储的硬件设备,它一次操作固定大小的块,而用户请求请求的可能是任意大小的数据块。因此,将数据从磁盘传递到用户空间,由内核负责数据的分解、再组合。

内存映射IO:就是复用一个以上的虚拟地址可以指向同一个物理内存地址。将内核空间的缓冲区地址(内核地址空间)映射到物理内存地址区域,将用户空间的缓冲区地址(用户地址空间)也映射到相同的物理内存地址区域。从而数据不需要从内核缓冲区映射的物理内存地址移动到用户缓冲区映射的物理内存地址了。
要求:①用户缓冲区与内核缓冲区必须使用相同的页大小对齐。②缓冲区的大小必须是磁盘控制器块大小(512字节磁盘扇区)的倍数---因为磁盘是基于块存储的硬件设备,一次只能操作固定大小的数据块。
用户缓冲区按页对齐,会提高IO的效率---这也是为什么在JAVA中new 一个字节数组时,指定的大小为2的倍数(4096)的原因吧。

四,JAVA中的IO,本质上是把数据移进或者移出缓冲区。
read()和write()系统调用完成的作用是:把内核缓冲区映射的物理内存空间中的数据 拷贝到 用户缓冲区映射的物理内存空间中。
因此,当使用内存映射IO时,可视为:用户进程直接把文件数据当作内存,也就不需要使用read()或write()系统调用了。
当发起一个read()系统调用时,根据待读取的数据的位置生成一个虚拟地址(用户进程使用的是虚拟地址),由MMU转换成物理地址,若内核中没有相应的数据,产生一个缺页请求,内核负责页面调入从而将数据从磁盘读取到内核缓冲区映射的物理内存中。对用户程序而言,这一切都是在不知不觉中进行。
总之,从根本上讲数据从磁盘装入内存是以页为单位通过分页技术装入内存的。

五,JAVA NIO中的直接缓存和非直接缓存

直接缓存:不是分配于堆上的存储,位于JVM之外,它不受JAVA的GC管理,相当于内核缓冲区。非直接缓存:建立在JAVA堆上的缓存,受JVM管理,相当于用户缓冲区。

根据上面第三点,将直接缓存中的数据写入通道的速度要快于非直接缓存。因为,连接到通道的另一端是文件(磁盘,FileChannel)或者网络(Socket通道),这些都是某种形式上的硬件。那么,对于非直接缓存而言,数据从缓冲区传递到硬件,要经过内核缓冲区中转。而对于直接缓存而言,就不需要了,因为直接缓存已经直接映射到内核缓冲区了。

IO 的底层实现问题的更多相关文章

  1. JAVA IO 以及 NIO 理解

    由于Netty,了解了一些异步IO的知识,JAVA里面NIO就是原来的IO的一个补充,本文主要记录下在JAVA中IO的底层实现原理,以及对Zerocopy技术介绍. IO,其实意味着:数据不停地搬入搬 ...

  2. Java IO、NIO、AIO知识总结

    本文主要讲述下自己对IO的理解,对IO的用法和细则可能没有顾虑到. 本文的理解基于以下几篇文章,他们对各自部分都讲的很细,对我理解IO提供了很大帮助. https://www.cnblogs.com/ ...

  3. IO测试工具之fio详解

    目前主流的第三方IO测试工具有fio.iometer和Orion,这三种工具各有千秋. fio在Linux系统下使用比较方便,iometer在window系统下使用比较方便,Orion是oracle的 ...

  4. 三、文件IO——系统调用

    3.1 文件描述符 文件IO 系统调用是不带缓存的,文件 I/O 系统调用不是 ANSI C 的组成部分,是 POSIX 的组成部分. 系统调用与C库: C库函数的IO 的底层还是调用系统调用 I/O ...

  5. IO测试工具之fio详解(转)

    http://www.cnblogs.com/raykuan/p/6914748.html 目前主流的第三方IO测试工具有fio.iometer和Orion,这三种工具各有千秋. fio在Linux系 ...

  6. IO流之字符流

    字符流产生的原因: 1.每次只能够读取一个字节或者一个字节数组,每次在需要转换成字符或者字符串的时候不是很方便2.不同的操作系统针对换行符的处理不方便3.有的时候会出现中文乱码(中文占两个字节,如果针 ...

  7. java对比IO和NIO的文件读写性能测试

    1. NIO采用更接近操作系统执行IO的方式:通道和缓存器:顾名思义,数据源的数据由缓存器通过通道进行传输. 2. 在JDK5之后,原始IO系统底层用NIO进行了优化,这可以通过sun公布的源码中找到 ...

  8. IO多路复用?我所理解的IO模式

    1:IO的过程 当我们调用系统函数read时,一般会经历两个阶段: 1:等待数据准备(waiting for the data be ready) 2:将数组从内核拷贝到进程(从内核态到用户态)(co ...

  9. linux系统IO操作

    本文重点说明下面内容: 什么是标准IO,什么是文件IO? 什么是Direct IO? O_SYNC标识有什么意义? 各个层面的缓存如何同步? 还在page cache中的脏页可以读写吗? IO路径上的 ...

随机推荐

  1. python学习-39 生成器总结

    总结 1.语法上和函数类似:生成器函数和常规函数几乎是一样的.它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,常规函数使用return语句返回一个值. 2.自动实现迭代器 ...

  2. go实现简单的tcp编程

    服务端的代码 package main import ( "fmt" "net" ) func main () { fmt.Println("star ...

  3. 解决IIS出现“由于权限不足而无法读取配置文件”的问题

    在部署IIS项目的时候,今天突然遇到了如下问题: HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效 详细错误信息: 由于权限 ...

  4. 普通表分区改造_rename方式

    一.需求 配合开发人员,对业务临时表进行分区改造(业务认为的临时表,只需要保留近一月数据,并非oracle临时表类型) 二.如下记录完整过程 开发需求 TS_PM 以time_key分区 .沟通明确方 ...

  5. 0160 十分钟看懂时序数据库(I)-存储

    摘要:2017年时序数据库忽然火了起来.开年2月Facebook开源了beringei时序数据库:到了4月基于PostgreSQL打造的时序数据库TimeScaleDB也开源了,而早在2016年7月, ...

  6. 将mdf文件copy到docker对应的目录下

    将mdf文件copy到docker对应的目录下: (<Docker-Container ID> 需要整体替换) docker cp /Users/Jay/Works/db/MyPost.m ...

  7. .net Core CLR

    .net Core CLR是开源的.大部分文件是C++写成.这样他就可以编译后再不同的平台运行. https://github.com/dotnet/coreclr

  8. Bminer

    Bminer https://www.bminer.me/zh/ Bminer: When Crypto-mining Made Fast¶ Bminer是一款为NVIDIA和AMD GPU深度优化的 ...

  9. 动态规划-最大算式 蓝桥杯ALGO-116

    问题描述 题目很简单,给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大.因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号 ...

  10. 【轻松一刻】Java制作字符动画

    前言 今晚闲来无事,整理了一下电脑中尘封已久的旧代码,看着那些年自己写过的代码,踩过的坑,顿时老泪纵横.正当在感叹之际,突然发现在“马克思”文件夹下出现了一个好玩的项目,那就是N年前刚学Java时写的 ...