找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1466

积分

0

好友

247

主题
发表于 8 小时前 | 查看: 1| 回复: 0

《“Hello World”程序的工作原理:从编译到执行》 中我们了解到,当 Shell 加载运行程序,或者程序输出信息时,它们并没有直接访问键盘、显示器或内存等硬件。这些操作都依赖操作系统提供的服务。

你可以将 操作系统 视为插在应用程序与硬件之间的一层软件,如下图所示。所有应用程序尝试操作硬件的请求,都必须通过操作系统这层“中间人”。

计算机系统的软件与硬件分层视图

操作系统主要有两大核心功能:

  1. 防止失控的应用程序滥用硬件资源。
  2. 为应用程序提供一套简单、统一的机制,来操控复杂且多样的底层硬件设备。

为了实现这些功能,操作系统引入了几个关键的抽象概念:进程虚拟内存文件,如下图所示。

操作系统提供的进程、虚拟内存与文件抽象

具体来说,文件是对 I/O 设备的抽象,虚拟内存是对主存和磁盘 I/O 设备的抽象,而进程则是对处理器、主存和 I/O 设备的整体抽象。下面我们来逐一探讨这些概念。

1. 进程

当一个程序(比如我们熟悉的“hello”程序)在现代操作系统上运行时,系统会营造一种假象:仿佛整个计算机只为此程序服务。它似乎独占着处理器、内存和 I/O 设备,代码指令在处理器上连续不断地执行,其代码和数据似乎是内存中唯一的对象。

这种强大的假象,正是通过进程这个概念来实现的。进程是计算机科学中最重要和最成功的概念之一。

进程是操作系统对一个正在运行的程序的抽象。在一个系统中,可以同时运行多个进程,每个进程都“感觉”自己在独占硬件。所谓“并发运行”,是指多个进程的指令在处理器上是交错执行的。

由于需要运行的进程数量往往远超 CPU 核心数,因此无论是单核还是多核系统,操作系统都需要通过一种机制让 CPU 在多个进程间快速切换,从而模拟出并发的效果。这种机制被称为上下文切换

操作系统负责跟踪每个进程运行所需的所有状态信息,这些状态统称为上下文,包括程序计数器(PC)、寄存器文件的当前值以及主存内容等。在任何时刻,单处理器系统只能执行一个进程的代码。

当操作系统决定将控制权从当前进程转移到另一个新进程时,就会进行一次上下文切换:保存当前进程的上下文,恢复新进程的上下文,然后将控制权交给新进程。新进程便会从它上次被暂停的地方继续执行。

下图展示了一个简单的上下文切换场景:

进程A与进程B的上下文切换示意图

假设场景中有两个并发进程:Shell 进程和 hello 进程。起初只有 Shell 在运行,等待用户输入命令。当用户输入命令要求运行 hello 程序时,Shell 会通过调用一个特殊的函数——系统调用——来执行请求,此时控制权会转移给操作系统。

操作系统随后保存 Shell 进程的上下文,创建一个新的 hello 进程及其上下文,接着将控制权转交给 hello 进程。待 hello 进程执行完毕终止后,操作系统再恢复 Shell 进程的上下文,并将控制权返还,Shell 继续等待下一个命令。

进程间的切换是由操作系统的内核管理的。内核是操作系统代码常驻内存的部分。当应用程序需要操作系统执行某项操作(如读写文件)时,就会执行一条系统调用指令,将控制权交给内核。内核执行完请求后,再将结果和控制权返回给应用程序。内核本身并非一个独立的进程,而是管理系统所有进程所需的代码和数据结构的集合。

2. 线程

传统上,我们认为一个进程只包含一个单一的执行流(控制流)。然而在现代系统中,一个进程可以由多个称为线程的执行单元构成。每个线程都运行在同一个进程的上下文中,并共享该进程的代码和全局数据。

由于线程比进程之间更容易共享数据,且通常更高效,因此在需要并行处理(如网络服务器)的场景中,线程成为了非常重要的编程模型。当系统拥有多个处理器(多核)时,多线程也能显著提升程序的执行速度。

3. 虚拟内存

虚拟内存是另一个核心抽象,它为每个进程提供了一个假象:每个进程都在独占使用整个主存。每个进程看到的内存都是一致的,称为虚拟地址空间

下图展示了 Linux 进程的典型虚拟地址空间布局(其他类 Unix 系统也类似)。地址空间最顶部区域保留给操作系统的代码和数据,这对所有进程都是一样的。底部区域则存放用户进程自己的代码和数据。

Linux进程虚拟地址空间布局

每个进程的虚拟地址空间由若干个功能明确的“区”构成,从低地址到高地址依次是:

  • 程序代码和数据:所有进程的代码都从一个固定地址开始,紧接着是存储全局变量的数据区。该区域的内容直接由可执行目标文件(如 hello 文件)初始化。
  • :位于代码和数据区之后。与代码/数据区在进程启动时就确定大小不同,可以在运行时动态扩展或收缩,例如通过调用 mallocfree 这类标准库函数。
  • 共享库:在地址空间的中部区域,存放着像 C 标准库、数学库这样的共享库的代码和数据。共享库的机制非常强大且高效。
  • :位于用户虚拟地址空间顶部,编译器利用它来实现函数调用。和堆一样,用户栈在程序执行期间可以动态伸缩。每次调用函数时栈会增长,函数返回时栈会收缩。
  • 内核虚拟内存:地址空间顶部的区域为内核保留。应用程序不能直接读写此区域内容或调用内核函数,而必须通过系统调用来请求内核执行操作。

4. 文件

在操作系统看来,文件仅仅是一个字节序列。这个简单的概念极其强大,因为它为应用程序提供了统一的视角,来看待系统中所有各式各样的 I/O 设备,包括磁盘、键盘、显示器,甚至网络。

所有输入输出操作,最终都通过一组称为 Unix I/O 的系统函数,以读写文件的方式来完成。例如,处理磁盘文件内容的程序员无需关心具体的磁盘技术细节,同一套程序可以在使用不同磁盘技术的系统上运行。这种抽象极大地简化了应用程序的开发。

理解进程、线程、虚拟内存和文件这些核心抽象,是掌握操作系统如何高效、安全地管理硬件资源的关键第一步。如果你对计算机系统底层原理有更浓厚的兴趣,欢迎在 云栈社区 深入探讨和交流,那里有更多关于计算机体系结构、编译原理等硬核知识的资源。




上一篇:企业网络安全指南:如何有效防范攻击者横向移动?
下一篇:MySQL关键字使用指南与数据类型选择实战建议
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-18 18:12 , Processed in 0.332113 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表