Linux 内存管理

内存管理

每个进程独占的内存空间(虚拟地址空间)都是独立的、相互隔离的。

虚拟地址空间分为内核空间和用户空间,站在进程的视角虚拟地址空间如下图:

用户空间从最低位开始排起:

TextSegment 是存放二进制可执行代码的位置

Data Segment 存放静态常量

BSSSegment 存放未初始化的静态变量

(这里就是把二进制执行文件的三个部分加载到内存里面)
堆(Heap)堆是往高地址增长的,是用来动态分配内存的区域

Memory Mapping Segment 这块地址可以用来把文件映射进内存

栈(Stack)主线程的函数调用的函数栈就是用这里的


进程的视角虽然可以看见内核空间,但是不能访问,如果需要进行更高权限的工作,就需要通过系统调用进入内核。

一旦进入了内核,就换了一副视角。刚才是普通进程的视角,觉着整个空间是它独占的,没有其他进程存在。当然其他进程也这样认为,因为它们互相看不到对方。但是到了内核里面,无论是从哪个进程进来的,看到的都是同一个内核空间。

内核的代码访问内核的数据结构,大部分的情况下都是使用虚拟地址的,虽然内核代码权限很大,但是能够使用的虚拟地址范围也只能在内核空间,只能用 30 号到 39 号这些编号,不能用 0 到 29 号,因为这些是被进程空间占用的。而且,进程有很多个。你现在在内核,但是你不知道当前指的 0 号是哪个进程的 0 号。 


上面介绍了虚拟地址空间的布局,但是它是如何映射成物理空间的呢?
答案是利用分段机制,如图:

分段机制下的虚拟地址由两部分组成:

段选择子:保存在段寄存器中。记录短号和特权等标识位,其中段号用作段表的索引。段表里面保存的是这个段的基地址、段的界限和特权等级等
段内偏移量:位于 0 和段界限之间
如果段内偏移量是合法的,就将段基地址加上段内偏移量得到物理内存地址,如下图:

分段机制虽解决了虚拟空间映射成为物理地址的问题,但由图可以看出分段机制的内存使用效率很低。所以Linux 更倾向于另外一种从虚拟地址到物理地址的转换方式,就是分页机制。


对于物理内存,操作系统把它分成一块一块大小相同的页,这样更方便管理,例如有的内存页面长时间不用了,可以暂时写到硬盘上,称为换出。一旦需要的时候,再加载进来,叫作换入。这样可以扩大可用物理内存的大小,提高物理内存的利用率。

换入和换出都是以页为单位的。页面的大小一般为 4KB。为了能够定位和访问每个页,需要有个页表,保存每个页的起始地址和页内偏移量,组成线性地址,就能对于内存中的每个位置进行访问了。如图:
虚拟地址分为两部分,页号和页内偏移。页号作为页表的索引,页表包含物理页每页所在物理内存的基地址。这个基地址与页内偏移的组合就形成了物理内存地址。


最后我们来看下进程运行状态下的内存结构(64位):

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值