计算机知识点的理解开悟后的分享(一)

对字节的理解

对字节的理解:都知道在计算机世界01能表示任何物体,那01的表示总有数量标准的规定吧,总不能你规定0101表示苹果,我010101表示苹果,01的数量不对等,这样肯定不行,那我到底用几个位来表示一个物品呢,所以我们规定了用字节来表示,一个字节由八个比特位,八个0/1,作为一个基本计量单位,这样一个'A'规定一个字节表示,一个汉字规定三个字节表示,而依据什么规则去用字节来表示字符呢 : 字符需要通过编码规则(如ASCII、UTF-8)转换为字节序列才能在计算机中存储,这样所有物品都由规则的用01来表示了(ps:就像是我们常说的一对一样,一对是几个呢,我们规定一对是两个,用一对当作基本统计单位一样)

我们来把把这个逻辑链条梳理得更具象化一点:

  1. 物理层(比特):计算机里只有电流的开关(0和1)。
  2. 计量层(字节) :为了方便管理,我们把8个0/1打包成一个**"字节"**,作为基本搬运单位。
  3. 逻辑层(编码) :为了解释这些0/1代表什么,我们查阅**"编码表"** (如UTF-8)。
    • 查到 01000001 -> 翻译为 'A'
    • 查到 1110xxxx... -> 翻译为 '中'
  4. 应用层(万物):无数的字节组合在一起,通过不同的解释规则,就变成了你看到的文章、图片(图片是字节的颜色坐标)、视频(字节的动态序列)。

这样我们就能更好的理解------01与万物的联系


对CPU、内存、硬盘之间联系的理解

都说CPU与硬盘之间的速度差异过大,内存来缓解,那是怎么缓解的呢,为什么要缓解呢?

CPU:内存:硬盘:

这里提到的"速度"通俗来说,就是**"从发出指令到真正拿到数据所需要等待的时间"**。

  • CPU :它的"速度"是指它处理指令的周期。现在的CPU主频很高,处理一个指令可能只需要 0.3纳秒 左右。
  • 内存 :它的"速度"是指CPU喊它要数据,它多久能把数据送过来。这个时间大约是 50~100纳秒。
  • 硬盘 :它的"速度"是指磁头找到数据位置(寻道)加上把数据读出来的时间。机械硬盘大约需要 5~10毫秒(即5,000,000纳秒),即便是很快的固态硬盘(SSD)也需要几十到上百微秒。

可以这样理解,a从老远的菜园摘菜送到厨房的时间,b把所有菜都洗好,切好,放好调料备用,c只需放菜到锅里,猛火爆炒5s出锅,b就相当于内存起到的作用

还有更完整的知识点点击这里


对CPU是如何不断工作的理解

CPU...(暂定)


虚拟内存空间的理解

ps :虚拟内存空间,那说白了,不就操作系同主要是出于减少内存消耗的目的"骗"一个进程有对应的内存空间,说是你这个进程的内存空间是0x0000到0xFFFF,其实也就在PCB的mm_struct 是这样写的,其实内存里啥也没有,直到CPU要拿或存这个进程的01码或者数据时,才会在内存中找一块空间把.exe文件的内容复制上来,其实也不是找一块,可能是找零零散散的内存空间,但操作系统可以内存映射啊,你这些零零散散的内存空间在内存里是这样的,但在映射前,比如说一群a1,a2,a3,a..,映射一群b1,b2,b3,b...,b1,b2,b3,b...是散的,但我a1,a2,a3,a....是完整有序的啊,它甚至有一个名字叫虚拟内存空间,从高地址到低地址,有栈,堆,.bss段,.data段,.rodata段,.text段。那就是PCB里的mm_struct里是这样写的,真找这个进程的内存数据时,是要通过mm_struct 里的记录的内容来找到进程对应的真正内存地址

  1. 程序的视角(虚拟内存):连续且有序

    操作系统为每个进程(程序)都提供了一个独立的、私有的虚拟地址空间。在这个空间里,内存布局是固定的、连续的。正如你所知,它通常被划分为几个区域:

    • 代码段 (Text Segment): 存放程序的机器指令,是只读的。
    • 数据段 (Data Segment): 存放已初始化的全局变量和静态变量。
    • BSS段: 存放未初始化的全局变量和静态变量。
    • 堆 (Heap): 用于动态内存分配(如 malloc),从低地址向高地址增长。
    • 栈 (Stack): 用于函数调用,存放局部变量、函数参数等,从高地址向低地址增长。

    从程序的角度看,这些区域就像一本页码连续的书,访问起来非常方便。

  2. 操作系统的视角(物理内存):分散且高效

    在真实的物理内存条上,情况完全不同。操作系统通过一个叫**分页(Paging)**的机制来管理内存。

    • 分页映射: 虚拟内存和物理内存都被划分成固定大小的块(例如4KB),分别叫"页"和"页框"。
    • 页表: 操作系统为每个进程维护一张"页表 ",这张表就像一个目录,记录了程序的哪个虚拟"页"对应物理内存中的哪个"页框"。
    • 非连续分配: 一个程序在虚拟空间中连续的几页,在物理内存中可以被分配到任何空闲的页框里,它们之间不需要是连续的。

    这种设计的好处非常多:

    • 突破物理限制: 可以让程序使用比实际物理内存更大的空间(部分数据可以暂时存放在硬盘上)。
    • 简化内存分配: 操作系统只需找零散的空闲页框即可,无需寻找一大块连续的空闲物理内存。
    • 内存保护: 每个进程都有自己独立的虚拟空间和页表,无法访问其他进程的内存,保证了系统的安全和稳定。

mm_struct的内容理解

mm_struct 在PCB结构体中,记录了在虚拟内存空间中的代码段,堆,栈的位置,还有虚拟地址与真实地址对应关系

  • mm_struct 是这张地图的总管家,它手里拿着两份核心文件:

    • VMA 链表 :记录了地图的区域规划 (哪里是代码,哪里是堆),以及这些区域对应硬盘上的哪个文件。
    • PGD(页表) :记录了地图上的坐标(虚拟地址)和**真实世界坐标(物理地址)**的对应关系。
  • VMA(虚拟内存区域):

    • 作用 :它是**"合法性检查员"** 和**"规则制定者"**。
    • 场景:当你访问一个地址时,内核(操作系统)会先看 VMA 链表。VMA 会告诉你:"这个地址属于堆区,你是可读可写的"或者"这个地址属于代码段,你只能读不能写"。如果地址不在任何 VMA 范围内,那就是非法访问(Segmentation Fault)。
    • 记录内容:它记录了"地图上的这块区域(比如 0x400000-0x500000)对应磁盘上的哪个文件(比如 exe 文件),是数据段,还是代码段,还是栈,还是堆"。
  • PGD(页全局目录,页表的一部分):

    • 作用 :它是**"极速导航员"**。
    • 场景 :当 VMA 确认地址合法后,CPU 的 MMU(内存管理单元)硬件会直接去查 PGD(以及后面的多级页表)。PGD 不负责讲规则,它只负责翻译:直接把虚拟地址转换成物理地址。按照映射规则,通过虚拟地址在硬盘中找到物理地址。
    • 记录内容:它记录了"虚拟页号 10 对应物理页框号 888"。

对函数栈帧的理解

栈帧的创建与销毁流程

我们以一个经典的C语言函数调用为例,看看底层发生了什么:

  1. 准备阶段(在调用者函数中)

    • 参数压栈: 编译器会生成指令,将函数的参数按照从右到左的顺序依次"压入"栈中。
    • 调用函数: 执行 call 指令。这个指令会做两件关键事:
      • 将下一条指令的地址(返回地址)压入栈,这样函数执行完后才知道该回到哪里。
      • 跳转到被调用函数的入口地址。
  2. 建立新栈帧(在被调用函数的开头)

    这是最关键的一步,通常由三条汇编指令完成,称为"函数序言(Function Prologue)":

    • push ebp:保存上一层函数的栈底指针(EBP),形成一个调用链。
    • mov ebp, esp:将当前的栈顶指针(ESP)的值赋给EBP。现在,EBP就成为了当前函数栈帧的固定基准点。
    • sub esp, N:将栈顶指针ESP向下移动N个字节,为当前函数的所有局部变量分配空间。

    至此,一个全新的、独立的栈帧就创建好了。

  3. 存储局部变量

    现在,栈帧已经建立,EBP是基准点。那么局部变量存在哪里呢?答案是:它们就存放在我们刚刚用 sub esp, N 开辟出来的空间里,通过相对于EBP的偏移量来访问。

    • 比如,第一个局部变量可能存放在 [ebp - 4] 这个地址。
    • 第二个局部变量可能存放在 [ebp - 8] 这个地址。
    • 而函数的参数,则可以通过 [ebp + 8]、[ebp + 12] 等正偏移量来访问。

    所以,栈并不是"知道"要存局部变量,而是编译器在编译时就已经计算好了需要多少空间,并生成了精确的指令来分配空间和通过偏移量访问它们。

  4. 销毁栈帧(在函数返回时)

    函数执行完毕,需要返回时,会执行"函数结语(Function Epilogue)"来清理现场:

    • mov esp, ebp:将栈顶指针ESP恢复到EBP的位置,相当于释放了所有局部变量占用的空间。
    • pop ebp:将栈中保存的上一层函数的EBP值弹出,恢复到EBP寄存器,回到了上一层函数的栈帧。
    • ret:从栈中弹出之前保存的返回地址,并跳转回去,程序继续执行。

整个过程就像搭积木,调用函数时搭上一块(创建栈帧),函数返回时拆掉这块(销毁栈帧),一切都有条不紊,完全由编译器和CPU的指令自动完成。


对数据段的理解

数据段里存放的绝对不是 01 这种指令码,而是数据的"真身"(二进制数值)。

为了让你彻底明白,我们需要区分**"动作"** 和**"对象"**。

  1. 核心区别:指令 vs 数据
  • 代码段(.text) :存放的是动作 。
    • 比如 01(假设的指令码)代表"加法"。这是告诉 CPU "去做什么"。
  • 数据段(.data) :存放的是对象 。
    • 比如 10(二进制 1010)。这是告诉 CPU "操作的具体数值是多少"。

打个比方:

  • 代码段 就像剧本,上面写着:"主角拿起苹果"。(这是指令)
  • 数据段 就像道具库 ,里面真的放着一个苹果。(这是数据)
  1. 深入底层:int count = 10; 到底长啥样?

当你写下 int count = 10; 这行代码,经过编译器编译后,它在磁盘上的可执行文件(比如 .data 段)里是这样的:

在数据段(.data)里:

这里只存数值,不存变量名(变量名在编译后通常就丢了,变成了地址)。

  • 内容 :就是数字 10 的二进制形式。
  • 样子 :在 32 位系统里,它通常长这样(十六进制表示):0A 00 00 00。
    • 这就是 10 的真身。CPU 读到这个内存地址时,它看到的不是"指令",而是"数值 10"。

在代码段(.text)里:

这里存的是搬运指令。

  • 为了让 count 变成 10,CPU 需要执行指令。
  • 指令 :类似于 MOV [地址], 10。
  • 样子 :这才会出现类似 C7 05 ... 这样的操作码(Opcode)。这条指令的意思是:"把数值 10 搬运到内存的某个地址去"。

ps : 不就是代码段里的指令写好了,要去哪里拿数据,数据段在那个地址放着数据


对程序运行阶段的总结

  1. 进程创建与账本建立 :双击 exe 后,操作系统首先创建 PCB(进程控制块),并初始化 mm_struct(内存描述符),这是管理内存的"总账本"。
  2. 虚拟地址空间规划(画地图) :加载器读取 exe 文件头,在虚拟地址空间中划定代码段、数据段、堆和栈的范围,但此时不分配任何物理内存。
  3. VMA 与文件映射 :mm_struct 通过 VMA(虚拟内存区域)记录虚拟地址与磁盘文件的对应关系(例如:虚拟地址 0x400000 对应 exe 文件的第 0 字节)。
  4. 首次执行与缺页异常:CPU 尝试执行第一条指令时,因页表为空触发"缺页异常",内核介入,分配物理页框并将代码从硬盘读入内存。
  5. 栈的自动分配:栈空间在虚拟内存中高地址向下增长。当栈指针移动触发缺页异常时,内核自动分配物理页,实现"按需增长"。
  6. 堆的延迟分配 :malloc 仅通过 brk/mmap 扩展虚拟地址范围,只有当程序真正读写堆内存时,才会触发缺页异常并分配物理页。
  7. 物理内存的碎片化与映射:虚拟内存是连续的,但对应的物理内存是离散的。通过页表(PGD)的映射,操作系统将零散的物理页框(Page Frame)拼接成连续的虚拟空间。
  8. 核心机制总结 :虚拟内存的本质是**"按需调页"**。操作系统通过"画饼"(虚拟地址)和"按需兑现"(缺页异常处理),实现了内存的高效利用和进程隔离。
相关推荐
Li_RuiQi11 小时前
DAgger方法演进_独立学习笔记
笔记·学习·计算机视觉
Li_RuiQi16 小时前
DAgger与交互式模仿学习_ACT学习笔记
笔记·学习
He BianGu16 小时前
【笔记】C# 中BindingFlags的详细作用
笔记·c#
AI视觉网奇16 小时前
turtle 入门教程笔记
笔记
跨知易知识产权17 小时前
美国专利确权是什么,和专利诉讼有什么不一样?
笔记
杨逢昌工厂6S管理17 小时前
126-杨逢昌6S三环体系:越做越乱的现场熵增机理与基准化治理——一线现场诊断笔记
经验分享·笔记·职场和发展·学习方法
悟道书生17 小时前
若依 RBAC 权限控制学习笔记
java·网络·笔记·sql·学习·vue
陈哈哈111117 小时前
折腾了半天,总算把 Vim 9.2 装明白了
笔记
陈哈哈111117 小时前
折腾了半天,总算把 OpenGL 的开发环境给装明白了
笔记
深圳老胡18 小时前
STM32F103 硬件 SPI 与软件 IO 模拟 SPI 最高速度差异详解
笔记·stm32·单片机·代码规范·1024程序员节