一台计算机可以抽象成下图:CPU中包含控制器和运算器,内存就是存储器。I/O设备就是输入设备和输出设备,如︰键盘、显示器、鼠标、硬盘、网卡。 常识普及:32位(x86)和64位(x64)机指的是CPU中ALU的宽度(CPU一次能够计算的数据的长度)
进程的加载指的是从I/O设备,磁盘加载到内存上的过程。 程序:磁盘上的一个可执行文件 进程:一个运行中的程序 可执行文件加载到内存上,由CPU执行其中的指令,这时操作系统就要分配一个进程控制块来管理加载到内存上的程序整个过程称之为进程。 分为两部分数据:
PCB程序加载到内存中的数据进程已经执行结束,但是进程对应的PCB结构还没有被系统释放。
分页:将内存空间划分成大小相等的区块(size很小),一个进程可以占用多个区块并且不要求其必须是连续的区块。(一页:4k) 操作系统为每一个进程维护一个页表
逻辑地址:是一个偏移地址,偏移量,页号+偏移量。比如一个变量:2 128; 物理地址:在物理内存上的真实地址。 同一个进程中,若访问的逻辑地址相同,那访问的肯定是同一块物理内存空间。
对于进程来说,使用的都是虚拟地址。每个进程维护一个单独的页表。何为页表? 页表是一种数组结构,存放着各虚拟页的状态,是否映射,是否缓存。
1)数组的索引号,表示虚拟页号 2)数组的值 若为null,表示未映射的页 若非null,第一位表示有效位,为1,表明缓存的页;为0,表明未缓存的页。 其余位表示缓存到的物理页号。
页表结构图如下: 进程执行时,当需要访问虚拟地址中存放的值时,步骤如下: 1)CPU会先找到虚拟地址所在的虚拟页(VP3),根据页表,找出页表中第3条的值。 判断有效位,为1,DRMA缓存命中,获根据物理页号,找到物理页中的内容,返回。 2)若有效位为0,产生缺页异常,调用内核缺页异常处理程序。 它会选择一个物理页(如PP4),作为牺牲页,将该页的内容刷新到磁盘文件。然后,把VP3映射的磁盘文件,缓存到该物理页。 页表中的第3条,有效位变1,同时,物理页号表号变为PP4。 3)缺页异常处理完毕后,返回中断前的指令,重新执行,此时缓存命中,执行1) 4)将找到的内容映射到高速缓存,CPU从高速缓存中获取该值,结束。
使用虚拟地址需要注意的问题 1)磁盘和主存传送页的活动叫做页面调度。页面调度会引起磁盘流量,如果程序的局部性不好,会频繁进行页面调度,叫做“缓存颠簸”。 操作系统会在内存中分配一块交换区作为缓冲区,来加速页面的调度。 2)一级页表占用的空间是比较大的,根据按需调度的原则,一般使用的是多级页表,即一级页表指向二级页表,这样大大压缩了页表的大小。 虚拟内存提供的三个重要的能力:
它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区 域,并根据需要在磁盘和主存之间来回传送数据,使得能够运行比内存大的多的进程。它为每个进程提供了一致的地址空间,从而简化了存储器管理它保护每个进程的地址空间不被其他进程破坏总结 当每个进程创建的时候,内核会为每个进程分配虚拟内存,这个时候数据和代码还在磁盘上,当运行到对应的程序时,进程去寻找页表,如果发现页表中地址没有存放在物理内存上,而是在磁盘上,于是发生缺页异常,于是将磁盘上的数据拷贝到物理内存中并更新页表,下次再访问该虚拟地址时就能命中了。
为什么引入缓冲区? 比如我们在磁盘读取数据的时候,先把数据放在缓冲区中,计算机再直接从缓冲区读取数据,等缓冲区中数据取完后再去磁盘读取,这样就可以大大减少对于磁盘的读写次数,再加上计算机对缓冲区的操作远远快于对磁盘的操作,所以应用缓冲区可以大大提高计算机的运行速度。 缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。 printf函数输出问题:其并不会直接将数据输出到屏幕,而是先放到缓冲区中,只有满足以下三种情况,才会输出到屏幕。
缓冲区满强制刷新缓冲区程序结束时 _exit()函数的作用:直接使进程终止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构; exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是图中的"清理I/O缓冲"一项。接受指令行参数 代码测试:
int main(int argc, char *argc[], char *envp[]) { printf("argc == %d\n",argc); printf("***********************"); int i = 0; for(;i <argc;i++) { printf("argv[%d] = %s\n",i,envp[i]); } printf("***********************"); for(i = 0;envp[i] != NULL;i++) { printf("envp[%d]:%s\n",i,envp[i]); } }今天就这么多!