在我们学习编程时,往往关注的是某种语言以及对应的使用环境,在此基础上完成我们的业务开发并部署运行。抛开这个最常见的层次,你是否自问过:我们开发的程序是如何在机器中运行的呢?这是计算机世界中最基础的问题。
要想理解这一点,需要先搞清楚这几个概念:
-
程序
程序就是源代码经过编译器编译后的二进制数据,是指令和数据的集合。比如printf("helloworld\n")这行代码,printf代表指令,“helloworld”代表数据。至于编程语言如何变成指令和数据,这是编译器的工作,不细说。这里主要指需要经过编译的源代码,对于某些脚本语言,执行所依赖的解释器其实也是普通的程序,最终反映到计算机当中都是二进制数据。程序一般安装到外存中,如硬盘或Flash,掉电后数据不丢失。 -
CPU
CPU是计算机的核心大脑,负责解析和运算最终转换成机器语言的程序内容,从功能上来看由寄存器、控制器、运算器、时钟构成。各模块功能如下:
寄存器:用来暂存指令、数据等处理对象。
控制器:负责把内存上的指令、数据等读入寄存器、并根据指令的执行结果来控制计算机。
运算器:负责运算从内存读入寄存器的数据。
时钟:负责发出CPU开始计时的时钟信号。
-
内存
内存指的是计算机的主存储器,其主要负责存储指令和数据,CPU通过内存地址值来读取或写入指令和数据。相对于外存,内存中的数据掉电后就丢失了。因为内存造价比外存贵多了,所以内存往往比外存空间小多了。当然,如果你够豪,给自己电脑装个1T大小的内存也是可以的。 -
外存
具有永久保存数据的存储器,最常见的就是硬盘和Flash。既然有了外存,为什么还要内存呢?我认为主要是因为内存读取速度比外存要快很多,能够配合CPU的高频率,提高运行速率。否则,CPU主频那么快,而外存读取那么慢,指令数据处理时,这不让CPU在那等着干着急嘛。
在理解了上面几个概念后,我们来看一下程序是如何运行的?程序启动后,被从外存中复制到内存,然后CPU根据时钟信号,控制器会从内存中读取指令和数据,通过对这些指令加以解析和运行,运算器就会对数据进行运算,控制器根据运算结果控制计算机。
那么,程序是如何被加载到内存中的呢?要理解这个,需要先了解程序在内存中的分布。以Linux环境为例,其他环境大体类似,如下表几部分:
名称 | 存储内容 |
---|---|
栈 | 局部变量、函数参数、返回地址等 |
堆 | 程序中动态分配的空间 |
BSS段 | 未初始化或初值为0的全局变量和静态局部变量 |
数据段 | 已初始化或初值非0的全局变量和静态局部变量 |
代码段 | 可执行代码(即CPU执行的机器指令)、只读常量(如字符串常量等) |
在将应用程序加载到内存空间执行时,操作系统或BootLoader负责代码段、数据段和BSS段的加载,并在内存中为这些段分配空间。栈也由操作系统分配和管理,堆由程序员自己管理,即显式地申请和释放空间。BSS段、数据段和代码段是可执行程序编译时的分段,栈和堆是运行时的分段。
【拓展】
我们思考一下嵌入式单片机的情况,一般嵌入式系统的硬件环境限制比较大,如CPU主频较低,内存(RAM)和Flash(ROM)空间很小。程序保存在ROM中,这种情况下,系统运行后,有时候程序就不会被加载到RAM中,而CPU直接从ROM中读取指令,RAM中只保存数据。这是因为,RAM空间很小,不足以存储程序;另外,因为CPU本身主频就不高,ROM的读取速度与CPU主频差距没有大型机那么大,完全可以接受。
以上,拙见~~~
网友评论