[操作系统学习记录#02]程序
一、汇编语言
汇编语言是操作系统学习中不可或缺的一部分,它直接面向硬件,帮助我们理解 CPU 如何执行指令、如何操作内存以及操作系统与程序之间的交互机制。通过学习汇编语言,可以更好地理解操作系统的底层原理。
- 与机器语言对应:每条汇编指令对应一条机器指令,操作对象通常是寄存器和内存。
- 直接操作硬件:可以读写内存、控制CPU寄存器、调用中断。
- 理解操作系统原理:操作系统在启动、调度、系统调用时,底层机制常涉及汇编指令。
- 调试与性能优化:掌握汇编语言有助于理解程序运行效率、排查底层问题。
汇编语言快速入门
汇编语言是一种面向计算机底层硬件的低级语言,不同于高级语言,它直接操作寄存器和内存。根据平台和用途,常见的汇编语言种类包括:
- x86 / x86-64 汇编:最常见的 PC 架构汇编,资料丰富,适合学习计算机原理和操作系统。
- ARM 汇编:用于手机、嵌入式设备,RISC 架构,指令集简单,适合嵌入式开发。
- MIPS 汇编:经典教学架构,简洁,常用于计算机组成课程。
- RISC-V 汇编:新兴开源架构,指令精简,适合现代教学和实验。
1️ 基础指令
最常用指令:
数据传输指令
MOV:寄存器、内存、立即数之间移动数据PUSH / POP:堆栈操作
1 | ; 把立即数 10 赋值给寄存器 AX |
解释一下:
MOV 寄存器, 立即数:直接赋值MOV [内存地址], 寄存器:把寄存器内容写入内存MOV 寄存器, [内存地址]:从内存取值到寄存器MOV 寄存器, 寄存器:寄存器之间复制数据
算术指令
ADD, SUB, INC, DEC:基本算术运算1
2
3
4
5
6
7
8
9
10
11; 将 AX 加上 5
ADD AX, 5
; 将 BX 减去 3
SUB BX, 3
; 寄存器 CX 自增 1
INC CX
; 寄存器 DX 自减 1
DEC DX
逻辑/位操作指令
AND, OR, XOR, NOT, SHL, SHR
跳转与比较
CMP+ 条件跳转(JE,JNE,JG,JL等)JMP:无条件跳转
1 | ; 比较 AX 和 BX |
长跳转说明:
- 在 x86 汇编中,跳转指令分为短跳(short jump,8-bit 位移)和长跳(near/far jump)
- 短跳:偏移量 -128 到 +127 字节,只能跳到附近代码
- 长跳:偏移量更大(16/32-bit),可以跳到远处甚至不同段
- 常用做函数调用或者跨段跳转
压栈弹出说明:
- 呃,我靠,我不知道怎么解释,反正,push指令就是:
1
2sub esp, 4 ; 栈顶下移 4 字节(为32位值腾出空间)
mov [esp], <一个你想压栈的值> ; 把值写入新的栈顶 - 呃,剩下的交给以后的我再去解释
- 我真服了,这玩意根本过不了aigc
二、应用程序在内存中的四个段
先介绍一下内存分片(Memory Fragmentation)
当操作系统或程序频繁进行内存的分配与释放时,内存空间会逐渐变得不连续,从而产生内存分片(fragmentation)。分片会导致系统有“足够的总内存”,却无法为某个程序分配连续的大块空间。
一、内存分片的分类
1. 外部碎片(External Fragmentation)
- 定义:当内存中的空闲块不连续,无法为一个需要较大连续内存的请求提供空间时,称为外部碎片。
- 原因:频繁分配与释放不同大小的内存块。
- 特点:空闲内存被分散成多个小块,即使总量足够,也无法整合为连续空间。
- 示意图:
内存空间(释放与分配后):
[已用][空闲][已用][空闲][已用][空闲]
↑ ↑ ↑
外部碎片区块(不连续)
2. 内部碎片(Internal Fragmentation)
- 定义:当系统以固定大小的块分配内存,而程序并未完全使用该块时,未使用的部分称为内部碎片。
- 原因:分配单位过大,或分配策略不够灵活。
- 特点:空间浪费发生在块内部。
- 示意图:
分配的内存块(每块4KB):
[程序A 3.2KB][程序B 2.7KB][程序C 4KB]
↑0.8KB浪费 ↑1.3KB浪费
二、解决方法
| 方法 | 适用场景 | 思路 |
|---|---|---|
| 内存紧缩(Compaction) | 操作系统层面 | 将分散的空闲块移动到一起,形成连续空间 |
| 分页(Paging) | 现代操作系统(如 Linux、Windows) | 将内存划分为固定大小的页(通常4KB),逻辑连续 ≠ 物理连续 |
| 分区 / 堆管理算法 | 应用层内存分配器 | 通过空闲链表、伙伴系统(Buddy System)等减少碎片 |
| 内存池(Memory Pool) | 程序频繁分配小块内存 | 预先分配一大片内存,由程序内部管理 |
三、分页机制与碎片的关系
分页机制的引入几乎彻底消除了外部碎片,但由于页的固定大小(4KB、2MB等),仍可能产生内部碎片。
逻辑页映射到物理页:
<无实物展示>
应用程序在内存中的四个主要段(从低地址到高地址)
当一个程序被加载到内存中运行时,操作系统会为它划分出多个功能不同的区域(段),每个段承担特定职责。这些段共同构成了程序的 逻辑地址空间(Logical Address Space),其地址分布从低到高依次为代码段、数据段、BSS段、堆、栈(堆与栈之间通常存在空闲地址空间)。
1. 代码段(Code/Text Segment)
- 核心内容:存放程序的 可执行机器指令(即编译后生成的二进制运行代码,如函数体内的执行逻辑)。
- 关键特性:
- 通常设置为 只读区域,防止程序运行过程中意外修改指令,避免逻辑混乱或崩溃。
- 在多进程环境中可共享:若多个进程运行同一程序(如同时打开多个相同软件),可共用同一份代码段,大幅节省物理内存占用。
2. 数据段(Data Segment)
- 核心内容:存放 已初始化的全局变量(如
int global_num = 10;)和 已初始化的静态变量(如static int static_num = 20;)。 - 关键特性:
- 初始化时机:程序加载到内存时,操作系统会根据可执行文件中记录的初始值,为该段变量分配空间并完成初始化。
- 生命周期:与程序运行周期一致,变量值从程序启动到退出始终存在,不会随函数调用结束而释放。
3. BSS 段(Block Started by Symbol)
- 核心内容:存放 未初始化的全局变量(如
int uninit_global_num;)和 未初始化的静态变量(如static int uninit_static_num;)。 - 关键特性:
- 自动清零:程序加载时,操作系统会自动将该段所有变量初始化为 0 值(或空指针),无需程序员显式赋值。
- 不占可执行文件空间:可执行文件中仅记录该段需分配的内存总大小,而非变量具体值,因此能减小文件体积。
4. 栈(Stack Segment)
- 核心内容:支撑函数调用过程,存放 函数返回地址(函数执行完后需回到的调用位置)、函数参数、局部变量(如函数内定义的
int local_num;)。 - 关键特性:
- 地址增长方向:与堆相反,从高地址向低地址收缩(函数调用时栈空间扩展,函数返回时栈空间回收)。
- 自动管理:由操作系统全程控制,无需程序员干预——函数调用时自动分配栈空间,函数执行结束后自动释放,避免内存泄漏。
- 栈顶维护:由专用寄存器(x86 架构的 ESP 寄存器、x86-64 架构的 RSP 寄存器)记录 栈顶指针,实时指向当前栈的最顶端位置。
5. 堆(Heap Segment)
- 核心内容:提供 动态内存分配 功能,存储程序运行中临时需要、大小不确定的数据(如动态创建的数组、对象,通过
malloc()、new等函数申请)。 - 关键特性:
- 地址增长方向:从低地址向高地址逐步扩展。
- 手动管理:需程序员显式调用分配函数(如
malloc)和释放函数(如free);若只分配不释放,会导致 内存泄漏,长期运行可能耗尽系统内存。
三、函数调用约定与堆栈图
四、c语言
按理来说应该说一下makefile?但我懒
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 ziHeng的个人博客!




