IO 的底层实现问题
最近在看 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 的底层实现问题的更多相关文章
- JAVA IO 以及 NIO 理解
由于Netty,了解了一些异步IO的知识,JAVA里面NIO就是原来的IO的一个补充,本文主要记录下在JAVA中IO的底层实现原理,以及对Zerocopy技术介绍. IO,其实意味着:数据不停地搬入搬 ...
- Java IO、NIO、AIO知识总结
本文主要讲述下自己对IO的理解,对IO的用法和细则可能没有顾虑到. 本文的理解基于以下几篇文章,他们对各自部分都讲的很细,对我理解IO提供了很大帮助. https://www.cnblogs.com/ ...
- IO测试工具之fio详解
目前主流的第三方IO测试工具有fio.iometer和Orion,这三种工具各有千秋. fio在Linux系统下使用比较方便,iometer在window系统下使用比较方便,Orion是oracle的 ...
- 三、文件IO——系统调用
3.1 文件描述符 文件IO 系统调用是不带缓存的,文件 I/O 系统调用不是 ANSI C 的组成部分,是 POSIX 的组成部分. 系统调用与C库: C库函数的IO 的底层还是调用系统调用 I/O ...
- IO测试工具之fio详解(转)
http://www.cnblogs.com/raykuan/p/6914748.html 目前主流的第三方IO测试工具有fio.iometer和Orion,这三种工具各有千秋. fio在Linux系 ...
- IO流之字符流
字符流产生的原因: 1.每次只能够读取一个字节或者一个字节数组,每次在需要转换成字符或者字符串的时候不是很方便2.不同的操作系统针对换行符的处理不方便3.有的时候会出现中文乱码(中文占两个字节,如果针 ...
- java对比IO和NIO的文件读写性能测试
1. NIO采用更接近操作系统执行IO的方式:通道和缓存器:顾名思义,数据源的数据由缓存器通过通道进行传输. 2. 在JDK5之后,原始IO系统底层用NIO进行了优化,这可以通过sun公布的源码中找到 ...
- IO多路复用?我所理解的IO模式
1:IO的过程 当我们调用系统函数read时,一般会经历两个阶段: 1:等待数据准备(waiting for the data be ready) 2:将数组从内核拷贝到进程(从内核态到用户态)(co ...
- linux系统IO操作
本文重点说明下面内容: 什么是标准IO,什么是文件IO? 什么是Direct IO? O_SYNC标识有什么意义? 各个层面的缓存如何同步? 还在page cache中的脏页可以读写吗? IO路径上的 ...
随机推荐
- python学习--12 基本数据类型
数字 int -int 功能 1.转换 例如: a = '123' # 字符串print(type(a),a)b = int(a) # 将字符串转换成intprint(type(b),b) 运算结果 ...
- 删除列表的三个方式(python)
del是个语句而不是方法 del member[1]:通过下标进行删除 del member:也可删除整个列表 remove():根据列表元素本身来删除,而不是通过下标 member.remove(' ...
- WUSTOJ 1246: 字符串排序(Java)
1246: 字符串排序 题目 输入n(n<100)个字符串,每个字符串长度不超过1000,将他们按字典顺序输出.更过内容点击标题. 分析 Java中的ArrayList()可以比较方便的 ...
- pandas数据结构之基础运算笔记
import pandas as pd import numpy as np s = pd.Series([1,3,5,6,8],index=list('acefh')) s.index # 读取行索 ...
- go 常量2
数值常量 数值常量是高精度的 _值_. 一个未指定类型的常量由上下文来决定其类型. 也尝试一下输出 needInt(Big) 吧. package main import "fmt" ...
- Task执行多次
项目中,曾经出现过启动时数据库连接数瞬间增大,当时并没有注意该问题. 后期,由于Task任务多次执行,才着手查看这个问题,经排查,由于tomcat中webapp配置多次,导致webapp被扫描多次(配 ...
- POJ1083(Moving Tables)--简单模拟
题目链接:http://poj.org/problem?id=1083 如图所示在一条走廊的两侧各有200个房间,现在给定一些成对的房间相互交换桌子,但是走廊每次只能通过一组搬运, 也就是说如果两个搬 ...
- JoinableQueue类与线程
生产者消费者的问题及其解决办法 问题 在之前的生产者消费者模型中,生产者和消费者只有一个, 那么生产者往队列里put几次,消费者就get几次,但是存在一个问题, 生产者不一定只有一个,消费者也不一定只 ...
- harbor小结
1.harbor是什么? docker容器是集装箱,harbor就是放集装箱的港湾. docker工具下有:①自带镜像库房:image ②容器管理清单 :container ③doc ...
- Numpy API学习
Numpy 常用API学习(全) 一.介绍 NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库 ...