我去,又又又被内存坑了

我去,又又又被内存坑了
文章图片
图片来自包
大家好 , 我是你们的老朋友轩辕 。
点进这篇文章的朋友 , 恭喜你们 , 又要收获新知识了~
这又是一篇非常硬核的技术文 , 建议配合一瓶怡宝或营养快线食用 , 效果更好哦 。
很多小伙伴在学操作系统的时候 , 学习到内存管理的部分时 , 都会接触到分段内存管理、分页内存管理 。
我去,又又又被内存坑了
文章图片
但很多人学完以后一头雾水:
到底现在用的是分段还是分页?
段寄存器这个东西现在还在用吗?
为什么在讲到虚拟地址翻译的时候 , 好像跟段又没有关系了呢?
之所有有这个问题 , 是因为很多同学看的教程很多都是偏理论的或者是过时的 , 根本不给你讲现代操作系统中实际的情况(关于这一点我已经吐槽很多次了) 。
今天轩辕就带大家把内存管理的这些疑问一次性弄清楚 , 分段还是分页 , 别再傻傻分不清楚了!
Let'sgo!
在开始之前 , 我们还是先来简单复习一下 , 操作系统书上讲到的Intelx86CPU架构下的分段式内存管理和分页式内存管理 。
分段式内存管理
早在16位的8086时代 , CPU为了能寻址超过16位地址能表示的最大空间(64KB) , 引入了段寄存器 。
通过将内存空间划分为若干个段 , 然后采用段基地址+段内偏移的方式访问内存 , 这样能访问1MB的内存空间了!
我去,又又又被内存坑了
文章图片
那时候 , 段寄存器有4个 , 分别指向不同的段 。
cs:代码段ds:数据段ss:栈段es:扩展段在那个时候 , 段寄存器中存放的是段基地址 , 注意 , 是一个地址 。
在通过ip寄存器读取指令的时候 , 实际上是cs:ip , 通过sp寄存器访问栈的时候 , 实际上是ss:sp 。
我看到网络上很多文章介绍分段式内存或者介绍段寄存器的时候就止步于此了 , 而事实上 , 进入32位时代后 , 情况已经发生了翻天覆地的变化 , 只讲上面这一部分内容实际上会误导很多人 。
变化1:
在32位时代 , 段寄存器又增加了两个:fs、gs , 这两个段寄存器有特殊用途 。
变化2:
段寄存器里面存放的不再是段基地址 , 而是一个叫段选择子的东西 。 注意 , 注意 , 一切的变化都从这里开始 。
段寄存器是16位的宽度 , 原来这16位是个物理内存地址 , 但现在 , 它是这样一个结构:
我去,又又又被内存坑了
文章图片
实际上 , 现在的段寄存器中存放的是一个号码 , 什么号码呢?是一个表格中表项的号码 , 这个表 , 有可能是全局描述符表GDT , 也有可能是局部描述符表LDT 。
那到底是哪个表?是由段选择子从低到高的第三位来决定的 , 如果这一位是0 , 则是GDT , 否则就是LDT 。
那这两个表又是啥 , 表里面装的又是什么 , 怎么来寻址呢?
这两个表的表项叫做段描述符 , 描述了一个内存段的信息 , 比如段的基地址、最大长度、访问属性等等一系列信息 , 它长这个样子:
我去,又又又被内存坑了
文章图片
CPU中单独添置了两个寄存器 , 用来指向这两个表 , 分别是gdtr和ldtr 。
在寻址的时候 , CPU首先根据段寄存器中的号码 , 通过gdtr或ldtr来到GDT/LDT中取出对应的段描述符 , 然后再取出这个段的基地址 , 最后再结合段内的偏移 , 完成内存寻址 。
我去,又又又被内存坑了