运行代码整个计算机会发生什么?面试必问

运行代码整个计算机会发生什么?

首先我们以一个C语言程序为例子

运行一个C/C++代码第一步:

在这里插入图片描述

  • 编译,优化(.c->.s,.asm)

    一个C/C++程序在点击运行的那一刻,首先这个程序经过预处理之后会被编译及优化,

    编译的过程设计到编译原理的相关知识,词法分析,语法分析,语义分析,中间代码生成,代码优化。将高级语言转换成等效的中间代码后者汇编程序代码。

    优化的话主要是对中间代码的优化,还有通过与机器的硬件结构相关而做出的一些优化,比如怎么充分利用机器的寄存器以及对内存的访问次数提高执行效率等等

  • 汇编(.s,.asm->.obj,.o,.a,.ko)

    汇编的过程是将汇编语言代码翻译成目标机器指令的过程,经过汇编之后得到相应的目标代码(机器指令集)。目标文件由段组成。通常一个目标文件中至少有两个段:

    1. 代码段:该段中所包含的主要是程序的指令。该段一般是可读和可执行的,但一般却不可写。

    2. 数据段:主要存放程序中要用到的各种全局变量或静态的数据。一般数据段都是可读,可写,可执行的。

  • 链接(.obj,.o,.a,.ko->.exe,.elf,.axf)

    扫描二维码关注公众号,回复: 13747633 查看本文章

    由汇编程序生成的目标文件,并不能立即被执行,可能某个源代码中的函数应用了另一个代码文件中的函数等等,因此需要链接,链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体,也就是可执行的程序。

操作系统要做什么?

那如果要运行一个可执行的程序(已经被编译汇编链接完)

  • 首先运行前,文件在磁盘中待着,此时只是以一堆二进制文件格式保存在磁盘中。

    而程序只有进入内存才能运行,但是要进入内存必须要服从os的进程调度,这个时候就涉及到操作系统的进程管理了,(细节可以看os的进程调度)

    然后因为内存就那么大,不可能为每个程序就直接分配内存,这个时候就用到了操作系统的内存管理的相关方法,比如虚拟内存等等,而虚拟内存会用到,每个进程有用独立的逻辑地址空间,内存被分为大小相等的多个块,称为(Page).每个页都是一段连续的地址。对于进程来看,逻辑上貌似有很多内存空间,其中一部分对应物理内存上的一块(称为页框,通常页和页框大小相等),还有一些没加载在内存中的对应在磁盘上。

  • 然后操作系统会进行程序的装载,也就是创建一个进程结构,它会有自己的一套虚拟地址、页表等结构。

    但是装载器不会把代码装载到物理内存中,而是用一个页表把代码在硬盘上的位置记录下来,只有在真正运行的时候才会加载到内存里面。

    最后,装载器会找到程序的入口地址,执行的时候,从入口地址开始读第一条指令。

  • 准备运行

    程序虽然还在硬盘里面,但是操作系统已经建立了一个进程,它有一套自己的虚拟地址、页表等高级数据结构。

    操作系统进行进程的调度,当轮到这个进程来的时候,才从装载器返回的入口点开始执行。

    CPU从程序入口处取出指令,但是这是一个虚拟地址,需要转换为物理地址。那么怎么转换呢?CPU会去查看页表,可以这个页表现在还指向的是硬盘中的地址,所以CPU会执行缺页中断处理程序

    最后CPU会从硬盘里面把代码加载入内存,之后CPU当然得把页表修改一下,这样才能反映数据已经进入内存呢。

  • CPU会不断的读数据、写数据,时间片到了,就把进程挂起来,也就是说进程其实不是独占CPU的,只是因为进程切换得非常快,从人类的角度来看,以为程序在同时执行一样。最后进程运行结束,内存中的数据会清理,覆盖。

操作系统为什么要这么做?

​ 操作系统为什么要那么麻烦的搞出什么内存映射、虚拟内存来,还不是因为资源有限,内存就那么大,程序又那么多,为了让更多的程序运行起来,有效的利用内存和CPU,只能使用这种方法了。

硬件系统要做什么?

我们以冯诺依曼计算机体系结构为例子: 在这里插入图片描述

  • 运算器:进行算数逻辑运算
  • 存储器:存放数据以及程序
  • 控制器:控制程序、数据、运算处理结果
  • 输入设备:将指令转换成机器可识别的机器语言
  • 输出设备:将指令转换成人可以识别的内容

而我们现代计算机的体系结构:存储器、算数逻辑(运算器)、控制单元(控制器),当然还有IO设备。

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

以一条机器语言为例子: ax^2+bx+c程序运行过程(程序代码已经成为了机器语言)

  1. 程序由IO设备送至计算机
  2. PC+1,得到程序首地址
  3. 程序开始启动
  4. 取数指令:PC–>MAR–>存储体–>MDR–>IR(指令寄存器)
  5. 分析指令:取出指令寄存器中的操作码,送入CU控制单元进行分析,得到指令意义
  6. 执行指令:取出IR中的地址码–>MAR—>存储体–>MDR–>ACC
  7. PC+1=PC,得到新的地址
  8. 取数指令:PC–>MAR–>存储体–>MDR–>IR(指令寄存器)
  9. 分析指令:取出指令寄存器中的操作码,送入CU控制单元进行分析,得到指令意义
  10. 执行指令:取出IR中的地址码–>MAR—>存储体–>MDR–>X

…… 最终出现结果 程序执行完毕

猜你喜欢

转载自juejin.im/post/7026622827658772487