1。物理内存和虚拟内存
物理内存只有内核才可以访问。
因为操作系统的进程与进程之间是共享CPU和资源的,为了防止进程之间互相影响就有了一个对主存的抽象概念:虚拟内存。虚拟内存使得应用程序以为自己有一块连续独立的存储空间,实际上是多个物理内存碎片。而虚拟内存和物理内存的对应关系存放在一个叫页表的地方。每个进程都有自己独立的页表。下图为上述三个概念的关系。
现在来总结下进程申请并访问物理内存的过程:
用户进程向系统发出内存申请请求
系统检查进程的虚拟内存是否用完,如有剩余则分配
系统将分配的虚拟内存创建内存映射 并将映射关系放入该进程的页表中。
系统将虚拟内存返回给用户进程,用户进程开始访问虚拟内存。
系统根据该进程中的页表去访问对应的物理内存。
2。内核空间和用户空间
操作系统的核心是内核,独立于普通的应用程序。可以访问受保护的内存空间也可以访问硬件设备。为了保护内核安全,所以将虚拟内存分为内核空间和用户空间。内核模块运行于内核空间,对应的进程处于内核态。用户模块运行于用户空间,对应的进程处于用户态。
3。Linux IO 读写的方式
轮询/IO中断/DMA
3.1 IO中断。 一个图就可以懂🦈
具体过程如下(图已经清晰了_为了以后回忆文字也贴上来
用户进程向 CPU 发起 read 系统调用读取数据,由用户态切换为内核态,然后一直阻塞等待数据的返回。
CPU 在接收到指令以后对磁盘发起 I/O 请求,将磁盘数据先放入磁盘控制器缓冲区。
数据准备完成以后,磁盘向 CPU 发起 I/O 中断。
CPU 收到 I/O 中断以后将磁盘缓冲区中的数据拷贝到内核缓冲区,然后再从内核缓冲区拷贝到用户缓冲区。
用户进程由内核态切换回用户态,解除阻塞状态,然后等待 CPU 的下一个执行时间钟。
3.2 DMA
其实我自己感觉只是节省的CPU一小部分的时间(将数据从磁盘缓冲区复制到内核缓冲区)
用户进程向 CPU 发起 read 系统调用读取数据,由用户态切换为内核态,然后一直阻塞等待数据的返回。
CPU 在接收到指令以后对 DMA 磁盘控制器发起调度指令。
DMA 磁盘控制器对磁盘发起 I/O 请求,将磁盘数据先放入磁盘控制器缓冲区,CPU 全程不参与此过程。
数据读取完成后,DMA 磁盘控制器会接受到磁盘的通知,将数据从磁盘控制器缓冲区拷贝到内核缓冲区。
DMA 磁盘控制器向 CPU 发出数据读完的信号,由 CPU 负责将数据从内核缓冲区拷贝到用户缓冲区。
用户进程由内核态切换回用户态,解除阻塞状态,然后等待 CPU 的下一个执行时间钟。
前面已经讲了Linux 读操作的两种方式具体步骤,下面讲一下读写整个过程的步骤。为了更好的理解零拷贝实现方式所以理解基础的读写过程也很重要。
4 传统的IO
在linux系统中通过read()方法读取文件到缓冲区,调用write()方法将缓冲区的数据输出到网络端口。
read(file_fd, tmp_buf, len);
write(socket_fd, tmp_buf, len);
4次上下文切换:读写时(用户态 <==> 内核态)
4次拷贝动作:DMA2次 + CPU2次
Ps:
4.1 传统的读操作
当应用程序调用read方法时会首先检查该数据是否存在于该进程的页内存中,如果存在直接返回 反之则需要进行一次完成的读操作。
2次上下文切换 一次CPU拷贝 一次DMA拷贝
1.用户进程通过read方法向内核发起系统调用。上下文由用户态变为内核态
2.CPU向DMA发送命令,使得DMA将磁盘的数据拷贝至内>核空间的读缓冲区。
3.CPU将内核空间的读缓冲区的数据拷贝至用户缓冲区。
4.上下文由内核态转为用户态
4.1 传统的写操作
写数据和读数据差不多啦就不写了
5 零拷贝实现方式的思路
- 用户态直接IO
Buffer 是对磁盘数据的缓存,而 Cache 是文件数据的缓存,
它们既会用在读请求中,也会用在写请求中。
这个文章也可以看一下 https://cloud.tencent.com/developer/article/1346483