【Linux】 存储分级的秘密
前言:欢迎各位光临本博客,这里小编带你直接手撕**,文章并不复杂,愿诸君**耐其心性,忘却杂尘,道有所长!!!!
《C语言》
《C++深度学习》
《Linux》
《数据结构》
《数学建模》
文章目录
- 1. 软件为啥非要先“搬”到内存?——存储分级的秘密
- 2. 两台电脑传文件:本质是“冯诺依曼”之间的快递
- 3. 操作系统:电脑的“小区物业”
- 4. 操作系统怎么管东西?——先描述,再组织
- 5. 系统调用:你和硬件之间的“银行柜台”
- 6. 进程管理:OS怎么“盯”着程序跑?
1. 软件为啥非要先“搬”到内存?——存储分级的秘密
咱们平时用软件(比如打开Excel),没运行时,它的代码和数据都躺在磁盘里——就像东西存放在家里的仓库。但一运行,这些东西必须先拷贝到内存,为啥?
因为电脑里的“干活的”(运算器、键盘这些硬件)都很“傲娇”:只跟内存打交道。这不是它们耍大牌,是计算机体系结构规定的——就像公司规定“报销只能找财务,不能直接找老板”。
背后更核心的原因是“存储分级”,简单说就是“越快的越小越贵,越慢的越大越便宜”,就像下图展示的:
- 最快的是CPU缓存:相当于你口袋里的零钱,拿起来最快,但装不了多少;
- 中间的是内存:像家门口的快递柜,比口袋能装,拿取速度也快;
- 最慢的是磁盘:就是家里的大仓库,能放很多东西,但找东西要半天。
而且软件跑多快,不看最快的CPU,只看最慢的环节(比如磁盘)——就像快递配送,飞机再快,最后一公里送得慢,整体还是慢。所以得先把磁盘里的程序“搬”到内存,让运算器能快速拿到数据,不耽误干活。
2. 两台电脑传文件:本质是“冯诺依曼”之间的快递
你给朋友传个照片,看似点一下“发送”就完了,其实背后是一套“快递流程”,而且本质是两台冯诺依曼体系电脑在交流(冯诺依曼体系就是电脑按“先存程序,再跑程序”的逻辑工作)。
具体流程就像这样:
你电脑的磁盘(你家仓库)→ 你电脑的内存(你家客厅)→ 你电脑的网卡(快递员)→ 网络(马路)→ 朋友电脑的网卡(朋友家快递员)→ 朋友电脑的内存(朋友家客厅)→ 朋友电脑的磁盘(朋友家仓库)。
一句话总结:文件先“搬”到内存,再交给“快递员”,送到对方后,先放内存,最后存仓库——这就是两台冯诺依曼电脑交流的核心逻辑。
3. 操作系统:电脑的“小区物业”
你用微信、玩游戏时,从不用管“键盘怎么识别输入”“内存够不够用”——这都是操作系统(OS) 在帮忙。它就像小区物业:
- 硬件(键盘、内存、磁盘)是小区里的电梯、水管(基础设施);
- 软件(微信、游戏)是小区业主;
- 物业(OS)的作用:帮业主协调用电梯(比如你打字时,OS让键盘把数据传给微信),不用业主自己去修电梯、管水管。
操作系统分两部分,就像下图里展示的结构:
- 内核:物业的“核心部门”,管最关键的事:
- 进程管理:安排业主的“活动”(比如让微信和浏览器轮流用CPU);
- 内存管理:分配小区“车位”(给每个程序分内存空间);
- 文件管理:管业主的“快递”(比如你存的照片、文档);
- 驱动管理:找“电梯维修师傅”(让硬件能正常工作,比如显卡驱动)。
- 其他程序:物业的“前台和服务”,比如:
- Shell(命令行):物业前台,你输
ls
“查快递”,前台就告诉内核去查文件; - 函数库:比如C语言的
printf
,像物业的“便民服务”,帮你简化操作。
- Shell(命令行):物业前台,你输
4. 操作系统怎么管东西?——先描述,再组织
不管是管进程、管文件,OS的核心逻辑就一句话:先描述,再组织。用学校管理的例子(像下图里的思路),一看就懂:
比如校长要管1000个学生,第一步不是直接喊名字,而是“先描述”:
给每个学生建一张“信息卡”,记着姓名、学号、班级——就像OS管进程时,先给每个进程建一张“信息卡”(后面会说的task_struct
),记着进程ID、状态、占用内存。
然后“再组织”:把这些“信息卡”按班级串起来(比如用链表,像串珠子)——OS就用链表、数组这些结构,把进程的“信息卡”组织起来。
这样校长要找“张三”,不用挨个教室问,直接查链表;OS要找某个进程,也不用遍历所有程序,直接查组织好的结构。
这里用C语言写个简单例子,帮你理解“描述+组织”:
// 1. 先“描述”:用结构体存每个学生的信息(相当于“信息卡”)
struct Student {char name[20]; // 姓名int id; // 学号char class[10]; // 班级struct Student* next; // 指向下一个学生,用来“组织”
};// 2. 再“组织”:用链表把学生串起来(相当于“按班级串信息卡”)
struct Student* student_list = NULL; // 链表头(第一个学生)// 新增学生 = 链表加节点(校长“收新学生”)
void add_student(char* name, int id, char* class) {struct Student* new_stu = malloc(sizeof(struct Student));strcpy(new_stu->name, name);new_stu->id = id;strcpy(new_stu->class, class);new_stu->next = student_list; // 插在链表头student_list = new_stu;
}// 查学生 = 遍历链表(校长“找学生”)
struct Student* find_student(int id) {struct Student* p = student_list;while (p != NULL) {if (p->id == id) return p;p = p->next;}return NULL;
}
其实世界上所有管理,都是先描述再组织:比如公司管员工(先记工号、部门,再按部门分组),超市管商品(先记条码、价格,再按货架分类)——OS也不例外。
5. 系统调用:你和硬件之间的“银行柜台”
OS有个矛盾:既不相信你(怕你乱改硬件,比如删了系统文件),又得帮你干活(比如你要读磁盘里的照片)。怎么解决?——开“柜台”,也就是系统调用。
这就像银行:你要取金库的钱(访问硬件),不能自己进金库(直接操作磁盘),得去柜台(调用系统调用),银行职员(OS)帮你取。
- 本质:OS提供的C语言函数接口,比如你要读文件,就调用
open()
;要写数据,就调用write()
。 - 关键规则:你写的程序想碰硬件,必须通过系统调用让OS帮忙——没有例外。
还有个容易搞混的点:库函数和系统调用的关系。比如你常用的printf("Hello")
(库函数),看起来简单,底层其实调用了write()
系统调用(让文字显示在屏幕上)。
简单说:库函数是“银行APP”,系统调用是“银行柜台”。你用APP转账(用库函数),比直接去柜台(写系统调用)方便,但APP最终还是会调用柜台接口。
用代码举个例子,看底层关系:
#include <stdio.h>
int main() {// 库函数:用起来简单,不用管底层怎么跟硬件交互printf("Hello World!\n"); return 0;
}// 编译后看底层:用gcc -S test.c生成汇编代码,会发现printf最终调用了write系统调用
// 结论:只要库函数要碰硬件(比如打印到屏幕),底层一定藏着系统调用
6. 进程管理:OS怎么“盯”着程序跑?
你打开的微信、浏览器,在OS里都叫“进程”——OS管进程,其实是管一个叫task_struct
的东西(也叫PCB,进程控制块)。
task_struct
就是进程的“身份证+说明书”,像下图里展示的,里面记着进程的所有关键信息:
- 进程ID(PID):相当于身份证号,唯一标识一个进程;
- 进程状态:是“正在运行”“等着CPU”还是“睡着了”;
- 占用资源:用了多少内存、CPU跑了多久;
- 打开的文件:比如进程打开的文档、图片。
OS管理进程,其实就是管理这些task_struct
——比如把它们用链表组织起来,要启动进程就加个节点,要停进程就删节点。
最后说几个常用的Linux命令,帮你实际操作进程(效果像下图里展示的):
# 1. 查看所有进程:像OS查所有“正在活动的程序”
ps axj# 2. 找特定进程:比如找“firefox”(浏览器)的进程
ps axj | grep firefox# 3. 杀掉进程:比如杀掉PID为1234的进程(PID从ps命令里看)
kill 1234# 4. 更改进程的当前路径:比如让进程的“当前工作目录”改成/home
cd /home # Shell命令,底层调用chdir()系统调用
如果想通过代码改进程路径,也很简单,就像下图示例的逻辑:
#include <unistd.h>
#include <stdio.h>
int main() {// 系统调用:直接改当前进程的路径int ret = chdir("/home");if (ret == 0) {printf("进程当前路径已改成 /home\n");}return 0;
}
简单说:你用命令或代码操作进程,其实是告诉OS“去改task_struct
的信息”——比如kill命令,就是让OS把某个task_struct
标记为“终止”,然后回收资源。