前言
从接触编程就开始使用 Git 进行代码管理,先是自己玩 Github,又在工作中使用 Gitlab,虽然使用时间挺长,可是也只进行一些常用操作,如推拉代码、提交、合并等,更复杂的操作没有使用过,看过的教程也逐渐淡忘了,有些对不起 Linus 大神。
出来混总是要还的,前些天就遇到了 Git 里一种十分糟心的场景,并为之前没有深入理解 Git 命令付出了一下午时间的代价。
先介绍一下这种场景,我们一个项目从 N 版本升到 A 版本时引入了另一项目的 jar 包,又陆续发布了 B、C 版本,但在 C 版本后忽然发现了 A 版本引入的 jar 包有极大的性能问题,B、C 版本都是基于 A 版本发布的,要修复 jar 包性能问题,等 jar 包再发版还得几天,可此时线上又有紧急的 Bug 要修,于是就陷入了进退两难的境地。
最后决定先将代码回退到 A 版本之前,再基于旧版本修复 Bug,也就开始了五个小时的受苦之路。
1 进程
进程与程序
操作系统之中最为通用的概念就是「进程」。与此相关的面试题以及各种技术优化策略也层出不穷,足以够证明它对于理解操作系统中举足轻重的地位。事实上,通过「进程」,程序员可以更为直观的理解自己所开发的软件,并且能够从中深刻的认识到操作系统在软件运行做了些什么。
简单来讲,进程就是正在执行的程序。每个进程都包含有属于自己的一段地址空间,可以看作是一部分内存空间。在这样的地址空间中,进程能够根据需要进行内存的读写。
地址空间里面一般包含可执行程序,以及对应程序的数据及其堆栈。与每个进程相关的还有一组资源,通常包括寄存器(包括程序计数器和堆栈指针)以及运行程序所需的所有其他信息。从这可以看出,程序本身只是指令、数据以及其组织形式的一种描述方式,而程序的实际的运行实例就是一个进程。
不过进程与程序也并不完全等同,他们不是简单的一一对应的关系,而是在不同层面的表现形式。他们的主要区别在于:
- 程序是进程的静态文本,而进程是执行程序的动态过程;
- 进程与程序不是一一对应,同一程序可在不同进程中运行,一个进程也可以执行多个程序;
- 程序是一种长期可保存的文本,进程是暂时的一次执行过程;
- 进程是操作系统分配调度的独立单位,而程序是操作系统层级之上的应用程序。
进程状态
从上面我们知道,进程可看作是程序运行的动态过程。那么为了更好的对进程进行描述,我们给运行中的进程定义了三种基本状态,包括就绪、执行和阻塞。
这就是所谓的三态模型,描述了进程在整个运行周期中状态变化。每个状态的转移过程可以通过下图来表示。
就绪状态
是指进程已经被分配到了所有必需的资源,除了CPU
。在这个状态下,进程处于箭在弦上随时待发的状态,只要一获得CPU
的执行权限,进程便会立刻执行,从而进入执行状态。
当有多个处于就绪状态的进程时,不同的进程会根据优先级被划分入不同的队列。一个因为时间片用完而进入就绪状态的进程会被划分入低优先级队列,而因为I/O
操作完成而进入就绪状态的进程,则会被划分入高优先级队列。
执行状态
是指进程正常运行的状态。而当处于执行状态的进程由于需要等待某个事件发送(通常为等待I/O
)时,就会放弃CPU
,从而进入暂时的阻塞状态。CPU
这时一旦空出,通过不同的调度算法,CPU
又会被分配给另一个就绪进程。
阻塞状态
相当于就绪状态和执行状态的一个缓冲状态。当处于执行状态的进程无法正常执行时,会先进入阻塞状态,等待需要的请求执行完成,再回到就绪状态,等待下一次的CPU