计算机的计算 : 第一,进程和线程对于 CPU 的使用;第二,对于内存的管理。
我们说每个进程应该有自己的内存空间。内存空间都是独立 的、相互隔离的。
如果执行一个程序, 哪些东西会存放在内存中?
代码需要放在内存里面,全局变量,常量字符串,函数栈 (函数调用),堆(malloc free), 然后malloc 还涉及到系统调用,内核部分也有一些东西要放在内存里 内核的代码要在内存里面; 内核中也有全局变量;每个进程都要有一个 task_struct; 每个进程还有一个内核栈; 在内核里面也有动态分配的内存;
内核空间: 多个进程看到同一内核空间, 但内核栈每个进程不一样
分段机制下的虚拟地址由两部分组成,段选择子和段内偏移量。
段选择子里面最重要的是段号,用作段表的索引。
段表里面保存的是 这个段的基地址、段的界限和特权等级等。
虚拟地址中的段内偏移量应该位于 0 和段界限 之间。
如果要访问段 2 中偏移量 600 的虚拟地址,我们可以计算出物理地址为,段 2 基地址 2000 + 偏移量 600 = 2600。这就是linux用的机制,在 Linux 里面,段表全称段描述符表(segment descriptors),放在全局描述符表 GDT(Global Descriptor Table)里面
对于 64 位的和 32 位的,都定义了内核代码段、内核数据段、用户代码段和用户数据段。
四个段选择子 : 分段可以做权限审核,例如用户态 DPL 是 3,内核态 DPL 是 0。当用户态试图访问内 核态的时候,会因为权限不足而报错
Linux 倾向于另外一种从虚拟地址到物理地址的转换方式,称为分页(Paging)。 对于内存长时间不要,可以暂时写到硬盘上,称为换出。一旦需要的时候,再加载进来,叫作 换入。这样可以扩大可用物理内存的大小,提高物理内存的利用率。
需要有个页表,保存每个页的起始地址,再加上在页内的偏移量,组成线性地址,就能 对于内存中的每个位置进行访问了。
虚拟地址分为两部分,页号和页内偏移。页号作为页表的索引,页表包含物理页每页所在物 理内存的基地址。这个基地址与页内偏移的组合就形成了物理内存地址。
32位下 : 页目录项 + 页表项 + 页内偏移量 恰好 = 32位
当然对于 64 位的系统,两级肯定不够了,就变成了四级目录,分别是全局页目录项 PGD(Page Global Directory)、上层页目录项 PUD(Page Upper Directory)、中间 页目录项 PMD(Page Middle Directory)和页表项 PTE(Page Table Entry)。