一、冯诺依曼体系结构
核心概念
冯·诺依曼体系结构,也称为普林斯顿体系结构 ,是当今几乎所有通用计算机(从智能手机到超级计算机)的设计蓝图。它由美籍匈牙利数学家约翰·冯·诺依曼及其同事在1945年发表的《First Draft of a Report on the EDVAC》报告中首次明确提出。
它的革命性思想在于将程序 像数据一样存储在计算机内存中,从而解决了早期计算机(如ENIAC)需要通过重新布线或设置开关来编程的难题。
核心五大组成部分
冯·诺依曼体系结构将计算机划分为五个基本部分,通过总线连接:

1. 运算器
功能: 执行所有算术运算(加、减、乘、除)和逻辑运算(与、或、非、比较)。
核心部件: 算术逻辑单元。
2. 控制器
功能: 是整个计算机的"指挥中心"。它从内存中读取指令,解码并控制其他所有部件协同工作以执行该指令。
运算器 + 控制器 合称为 中央处理器。
3. 存储器
功能 : 用于存储程序(指令序列) 和程序需要处理的数据。其特点是可寻址、可按地址读取或写入信息。
关键特性 : 程序和数据共存于同一存储器中,没有物理上的区分。这是冯·诺依曼结构的灵魂所在。
4. 输入设备
功能: 将外部的信息(程序和数据)输入到计算机中。例如:键盘、鼠标、触摸屏、扫描仪等。
5. 输出设备
功能: 将计算机处理的结果输出到外部世界。例如:显示器、打印机、音响等。
核心设计原则(三大要点)
1. 存储程序
这是最核心的原则。指令(程序)和数据以二进制形式不加区别地存储在同一个线性编址的内存中。这意味着计算机可以通过修改内存中的内容来改变其任务,使其变得"通用"。
2. 顺序执行
CPU通常顺序地 从内存中读取指令并执行(即一条接一条)。执行顺序由一个称为程序计数器 的寄存器决定,它存放下一条要执行的指令地址。当然,指令本身可以改变PC的值来实现跳转(如循环、判断)。
3. 五大部件组成
如上所述,计算机必须由这五个基本部件构成,并通过系统总线(数据总线、地址总线、控制总线)进行通信。
工作流程(冯·诺依曼循环)
CPU的工作是一个周而复始的循环,称为 "取指-译码-执行"循环:
1. 取指 : 控制器根据程序计数器 中的地址,从内存中读取一条指令。
2. 译码: 控制器分析该指令,确定需要执行什么操作(如加法)以及操作数在哪里。
3. 执行: 控制器命令相关部件(如运算器、内存、输入/输出设备)完成该指令指定的操作。
4. 更新计数器: 程序计数器增加,指向下一条指令的地址(除非当前指令是跳转指令,会修改计数器)。
- 重复步骤1,开始下一个循环。
二、操作系统(Operator System)
核心定义
操作系统 是一组系统软件程序的集合,它管理计算机硬件资源,控制程序执行,并为用户和其他软件提供公共服务和便利的接口。
简单比喻:
1. 硬件是身体(CPU是大脑,内存是思维空间,硬盘是长期记忆,键盘/鼠标是感官)。
2. 操作系统是心智与人格(它协调身体各部分,决定如何思考、如何反应,提供你与外界的交互方式)。
3. 应用程序是技能(写字、画画、计算,这些技能需要心智和身体配合才能完成)。
三、进程
1.基本概念
进程=内核数据结构(task_struct)+程序的代码和数据
其中task_struct是linux内核中的一种数据结构,被装载到内存中并且包含着进程的信息
task_struct
以下保留了核心的内容:
cpp
struct task_struct {
/* 1. 标识信息 - 最重要 */
volatile long state; // 进程状态(运行/睡眠/停止等)
int exit_state; // 退出状态
pid_t pid; // 线程ID(调度单位)
pid_t tgid; // 线程组ID(传统进程ID)
/* 2. 家族关系 */
struct task_struct __rcu *parent; // 父进程
struct list_head children; // 子进程链表
struct list_head sibling; // 兄弟进程链表
struct list_head tasks; // 所有进程链表节点
/* 3. 内存管理核心 */
struct mm_struct *mm; // 用户空间内存描述符
struct mm_struct *active_mm; // 活动内存描述符(内核线程用)
/* 4. 调度核心 - 决定谁运行 */
int prio; // 动态优先级
int static_prio; // 静态优先级(nice值相关)
unsigned int policy; // 调度策略(CFS/实时等)
const struct sched_class *sched_class; // 调度类
struct sched_entity se; // CFS调度实体(红黑树节点)
struct list_head run_list; // 运行队列节点
/* 5. 信号处理 */
struct signal_struct *signal; // 指向信号结构
struct sighand_struct *sighand; // 信号处理函数表
sigset_t blocked; // 阻塞的信号掩码
struct sigpending pending; // 待处理信号
/* 6. 文件系统 */
struct files_struct *files; // 打开的文件表
/* 7. 命名空间(容器化基础) */
struct nsproxy *nsproxy; // 命名空间代理
/* 8. 时间统计 */
u64 utime, stime; // 用户/内核态CPU时间
u64 start_time; // 进程启动时间
/* 9. 凭证(安全) */
const struct cred __rcu *cred; // 执行凭证(uid/gid/权限)
/* 10. 栈信息 */
void *stack; // 内核栈指针
/* 11. 线程特定 */
struct thread_info *thread_info; // 底层线程信息
/* 12. 通信相关 */
struct sysv_sem sysvsem; // System V信号量
struct list_head ptraced; // 被跟踪的进程列表
/* 13. 杂项 */
char comm[TASK_COMM_LEN]; // 可执行程序名
int exit_code; // 退出代码
unsigned int flags; // 进程标志位
};
最关键的10个字段:
cpp
struct task_struct {
// 1. 我是谁?
long state; // 状态:我当前在干什么?
pid_t pid; // 唯一标识符:我的ID是什么?
pid_t tgid; // 我属于哪个进程组?
// 2. 我从哪来?
struct task_struct *parent; // 我的父亲是谁?
// 3. 我的私人空间在哪?
struct mm_struct *mm; // 我的用户态内存地图
// 4. 我该怎么被调度?
int prio; // 我的优先级
struct sched_entity se; // 我在调度器队列中的位置
// 5. 我能访问什么文件?
struct files_struct *files; // 我打开了哪些文件
// 6. 我有什么权限?
const struct cred *cred; // 我的用户身份和权限
// 7. 我收到了什么信号?
struct sigpending pending; // 别人发给我的信号
// 8. 我的名字?
char comm[16]; // 我的程序名(前16个字符)
};
内存中的嵌套世界
RAM、OS和tack_struct之间有着什么样的关系呢??由图我们可知,task_struct在OS中,task_struct管理的代码和数据在RAM中,OS又在RAM中
bash
|-----------------------------------------------------|
| 【整个物理内存空间】 |
|-----------------------------------------------------|
| |
| +-----------------------------------------------+ |
| | 【操作系统内核空间】 | |
| | (内核态,受保护,用户程序不能直接访问) | |
| | | |
| | +---------------------------------------+ | |
| | | OS内核代码和数据 | | |
| | | - 内核本身的指令代码 | | |
| | | - 全局内核数据结构 | | |
| | | - 设备驱动程序 | | |
| | | | | |
| | | +-----------------------------+ | | |
| | | | 【task_struct实例们】 | | | |
| | | | (在堆或特定区域动态分配) | | | |
| | | | • task_struct A | | | |
| | | | • task_struct B | | | |
| | | | • task_struct C | | | |
| | | | ... | | | |
| | | +-----------------------------+ | | |
| | +---------------------------------------+ | |
| +-----------------------------------------------+ |
| |
| +-----------------------------------------------+ |
| | 【用户空间】(每个进程独立一份) | |
| | (用户态,进程间隔离) | |
| | | |
| | +--------+ +--------+ +--------+ | |
| | |进程A的 | |进程B的 | |进程C的 | ... | |
| | |虚拟内存| |虚拟内存| |虚拟内存| | |
| | +--------+ +--------+ +--------+ | |
| +-----------------------------------------------+ |
| |
|-----------------------------------------------------|
2.进程状态
Linux的7种进程状态
R (Running/Runnable) - 运行或可运行
进程正在CPU上执行或在就绪队列中等待调度。注意:Linux将"就绪"和"运行"都归为R状态。
S (Interruptible Sleep) - 可中断睡眠
进程正在等待某个事件完成(如I/O、信号),这种睡眠可以被信号唤醒。
D (Uninterruptible Sleep) - 不可中断睡眠
进程正在等待不可被信号中断的I/O操作(通常是磁盘I/O)。这是导致进程无法被kill -9杀死的常见原因。
T (Stopped) - 暂停状态
进程被信号(如SIGSTOP)暂停执行,可通过SIGCONT信号恢复运行。
t (Tracing stop) - 跟踪暂停
进程被调试器暂停(如ptrace),用于单步调试等情况。
Z (Zombie) - 僵尸状态
进程已终止,但其退出状态尚未被父进程回收(wait())。僵尸进程不占用内存但占据进程表项。
X (Dead) - 死亡状态
进程完全终止,即将被系统清理。这个状态极短暂,通常观察不到。
进程状态查看
bash
ps axj | grep xxxx
第一部分:ps axj
bash
ps # process status,进程状态命令
a # 显示所有用户的进程(包括其他用户的)
x # 显示没有控制终端的进程(如守护进程)
j # 显示任务格式(包含更多信息:PID、PPID、PGID、SID等)
//输出实例:
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 0:01 /sbin/init
1 456 456 456 ? -1 Ssl 0 0:00 /usr/bin/docker
bash
列位置 字段 含义
1 PPID 父进程ID
2 PID 进程ID
3 PGID 进程组ID
4 SID 会话ID
5 TTY 控制终端
6 TPGID 终端进程组ID
7 STAT 进程状态
8 UID 用户ID
9 TIME 累计CPU时间
10+ COMMAND 命令行/进程名
第二部分:|
管道符号,将ps axj的输出作为grep xxxxx的输入
第三部分:grep xxxxx
bash
grep # 文本搜索工具
xxxxx # 要搜索的模式(可以是进程名、关键字等)
整体含义:
ps axj | grep xxxxx = 在所有进程信息中,查找包含"xxxxx"关键字的行
3.进程优先级
基本概念
进程优先级是操作系统调度器决定哪个进程先获得CPU时间的依据。优先级高的进程会更频繁地获得CPU时间片。
查看系统进程
bash
ps -al
得到以下结果:
bash
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 17207 17188 0 80 0 - 47970 do_wai pts/1 00:00:00 su
4 S 1000 17208 17207 0 80 0 - 28921 do_wai pts/1 00:00:00 bash
0 R 1000 17228 17208 0 80 0 - 38332 - pts/1 00:00:00 ps
UID:代表执行者的身份
PID:代表进程的代号
PPID:代表这个进程由哪个进程衍生而来,为其父进程
PRI:代表进程可被执行的优先级,越小优先级越大
NI:代表这个进程的nice值 nice:[-20,+19]
更改进程优先级
top->"r"->输入进程的PID->输入nice值
PRI(最终)=PRI(默认:80)+nice