文章目录

  • 分段
  • 分页
    • 多级页表
    • 快表(TLB)
  • 段页式
  • Linux

Linux 内存管理 | 物理内存管理:内存碎片、伙伴系统、slab分配器
Linux 内存管理 | 虚拟内存管理:虚拟内存空间、虚拟内存分配

在前两篇博客中,我介绍了虚拟内存与物理内存的管理方式,那么对于操作系统来说,它是如何管理它们两个之间的关系的呢?如何进行地址的映射呢?

在早期的计算机中,程序是直接运行在物理内存上的,所以其通常都会面临以下几种问题

  1. 地址空间不隔离
  2. 内存使用效率低
  3. 程序运行的地址不确定

为了解决这些问题,我们又引入了虚拟内存这个概念,但是虚拟内存是如何解决这个问题的呢?它与物理内存又是如何进行映射的呢?这就是本篇博客所要讲的内容。

对于操作系统来说,通常解决这个问题的方式有三种,一种是内存分页,另一种是内存分段,以及两者相结合的段页式


分段

在最开始时,人们采用的是分段的方法,为了简化地址管理,所以将虚拟内存空间中的虚拟内存按照其逻辑划分为代码段、数据段、堆段、栈段几部分

通过段寄存器中的段表,来将虚拟地址与物理地址进行映射。段表中存储了每一个逻辑段的段号对应的物理内存的起始地址

对于每一个在虚拟内存中存储的数据,其虚拟地址都以其所在的段号以及段内偏移组成。

因此虚拟地址与物理地址的转换方式如下

  1. 根据虚拟地址中的段号查询段表
  2. 根据段表查询到对应的段的物理内存起始地址
  3. 物理内存起始地址加上段内偏移,即为其对应的物理地址


如上图,例如变量A段号为2,段内偏移为500。首先根据段号查询段表,得知物理内存起始地址位于3000的位置,接着找到对应的起始地址,加上段内偏移500,此时3500的位置即为其对应的物理地址。

通过分段的方式,我们解决了上面所说的问题1和问题3,但是对于内存的使用效率,分段仍然存在以下两个问题

  1. 内存碎片
  2. 内存交换的效率低

为什么会存在内存碎片的问题呢?

在上面的讲解中可以看出,在分段存储中,一个段内可能保存有多个变量,而这些变量都是从同一个物理地址起始位置开始偏移。因此在物理内存中,同一个段中的数据使用了连续的地址空间

例如我们有1G的物理内存,倘若我们运行了512M的程序A,接着运行了128M的程序B,128M的程序C。剩余内存为256M

倘若我们此时结束程序B,释放内存,此时总剩余空间为384M

倘若我们此时需要运行300M的进程D,但是这时候就会因为剩余空间不连续,导致我们的程序无法运行,这也就是我们常说的内存外碎片问题。

那么如何解决这个问题呢?这就会使用到内存交换。例如上面那种情况,我们就会将程序C写入硬盘的SWAP分区(交换分区,用于内存和硬盘的空间交换)。紧接着再将其从硬盘中读取回来,让其紧挨着程序A的那块内存,这样就能保证后面的空闲内存都是连续的了。

为什么内存交换的效率低呢?

由于分段对物理内存的映射是以程序为单位,按照其逻辑进行分段映射,如果我们的内存不足,那么被换入换出到硬盘中的都是整个程序,这样就必然会造成大量的磁盘访问操作,总所周知,磁盘IO的速度特别慢,因此就会严重影响我们的访问速度。

根据程序的局部性原理,当一个程序在运行时,在某个时间段内,它只是频繁地用到了一小部分数据,也就是说程序中的很多数据其实在一个时间段内都是不会被用到的。

而我们分段的最大问题就在于其以程序为单位进行映射,因此我们只需要使用更小粒度的存储单位,就可以解决这个问题,大大的提升内存的使用率。因此在后续的设计中,就以作为基本单位,这也就是分页机制的由来


分页

分页就是将内存空间人为地划分成固定大小的页,每一页地大小由硬件决定,在Linux中,一页是4KB

与段表类似,虚拟地址与物理地址的映射是通过MMU(内存管理单元)中的页表来完成的。

页表中不仅保存了页号,物理内存地址,还保留了该物理页的访问权限,用以实现对页的访问控制

在分页机制下,虚拟地址由页号以及页内偏移组成

因此在分页机制下,虚拟地址与物理地址的转换方式如下

  1. 根据虚拟地址中的页号查询页表
  2. 根据页表查询到对应的页的物理内存起始地址
  3. 物理内存起始地址加上页内偏移,即为其对应的物理地址

如下图

当进程需要访问物理地址时,此时CPU就会通过MMU中的页表,来找到对应的物理地址。

讲了这么多,再次回到之前的问题,分页是如何解决分段的内存利用率低的问题的呢?

主要就是依靠以下两方面来完成的

1、使用更低粒度的内存单位
分段所面临的最大问题,无非就是内存碎片以及交换效率低。

导致内存碎片最大的原因就是各个逻辑段的数据需要连续存储,而逻辑段又过大,导致我们需求大量的连续空间。而当我们所有的内存分配释放都以页为单位时,就能够很好的解决这个问题了。

而当内存空间不够时,我们需要进行将内存中的数据暂时写入到硬盘中,之后再重新写回来这样的换入换出操作。而使用页为单位后,即使我们还是需要进行磁盘IO,但是由于我们交换的容量仅仅只有几个页,所以也不会花费过多的时间。

2、不需要将程序一次性加载进内存,什么时候需要,什么时候加载。
按照前面说的,为了满足程序的局部性原理。所以为了能够尽可能提高内存的利用率,在建立了虚拟内存空间后并不会直接分配物理内存,而是在我们程序运行中需要用到的时候,再将其加载进内存中。

所以如果在页表中查找不到时,此时就会由内核的请求分页机制产生缺页中断,然后进入内核态中分配物理内存、更新进程页表,最后再返回用户态,恢复进程的运行。


在上面所介绍的页表中,有一个非常致命的缺点,就是空间占用大

在 Linux中,可以并发的执行多个进程,而每个进程都有其自己的虚拟内存空间,那么也自然都有自己独有的页表。在32位Linux系统下,我们的虚拟内存空间的大小为4G,而每页的大小为4K,这也就意味着我们至少有2^20个内存页,倘若每个页表项为4Byte,那么每个页表大小也至少为4M

倘若我们此时并发了两百个进程,那么占用则高达800M,即使是在现在,这个数字也是非常庞大的,因为并发数百个进程是非常常见的情况,更别提64位的操作系统,随着寻址范围的增加,页表将更为庞大。

为了解决这个问题,就引入了多级页表


多级页表

我们将一级页表再进行分页,分成1024个二级页表,并且每个二级页表中存有1024个页表项,形成如下的二级分页的结构。

虽然分级乍一看花费的物理内存变多了,但是实际上对于大多数程序来说,其使用到的空间远未达到 4G,所以会存在部分对应的页表项都是空的,根本没有分配。而对于已分配的页表项,如果存在最近一定时间未访问的页表,在物理内存紧张的情况下,操作系统会将页面换出到硬盘,也就是说不会占用物理内存。

如果某个一级页表的页表项没有被用到,也就不需要创建这个页表项对应的二级页表了,即可以在需要时才创建二级页表。假设每个二级页表大小为4M(1024 * 4K),而我们用到的一级页表只有20%

在这种情况下,页表所占用的物理内存就只有4K + 20% * 4M,即0.804M,比起只用了一级页表的4M,大大的节约了内存。

而在64位系统中,两级页表是肯定不够用的,因此又演变成了四级目录

  • 全局页目录项 PGD
  • 上层页目录项 PUD
  • 中间页目录项 PMD
  • 页表项 PTE

结构如下图所示


快表(TLB)

多级页表虽然解决了空间占用大的问题,但是由于其复杂化了地址的转换,因此也带来了大量的时间开销,使得地址转换速度减慢。

如果要解决这个问题,那么最简单的方式就是降低查询页表的频率,那么如何实现呢?这时候就需要用到缓存的技术

与我之前在Redis系列博客中所提到的,对于热点资源,我们可以将其提前缓存下来,到以后使用时就可以直接到缓存中查找。对于操作系统来说,也是这么一个道理。

在操作系统中,这个缓存就是CPU中的TLB,也就是我们通常所说的快表。我们将最常访问的几个页表项存储到TLB中,在之后进行寻址时,CPU就会先到TLB中进行查找,如果没有找到,这时才会去查询页表。


段页式

虽然分段和分页各有优缺点,但他们直接并不是对立的,所以如今大部分的内存管理方式,都是将分段与分页相结合,也就是我们常说的段页式

它的原理非常简单,就是先对虚拟内存空间进行分段管理,然后再对每一个段进行分页管理。如下图

所以此时的虚拟地址结构,就由段号、段内页号、页内偏移所组成。此时对于每个进程来说,都会建立一个段表,而对于段表中的每一个段,又会再分别建立一个页表,如下图

所以此时的虚拟地址转换为物理地址,就需要以下三个步骤

  1. 访问段表,得到页表的起始地址
  2. 访问页表,得到物理页的起始地址
  3. 访问物理页,加上页内偏移,得到实际的物理地址

这种方法虽然增加了系统开销以及硬件成本,但是内存的利用率得到了巨大的提升。


Linux

由于硬件问题的限制,Linux 内存主要采用的是页式内存管理,但同时也不可避免地涉及了段机制。

在往常的机制中,地址的转换流程如下

但是在Linux中,并没有逻辑地址这一说(所有段起始地址相同),因为其将段机制进行了弱化,此时段只用于进行访问控制以及内存保护

Linux 系统中的每个段都是从 0 地址开始的整个 4GB 虚拟空间(32 位环境下),也就是所有的段的起始地址都是一样的。
这意味着,Linux系统中的代码,包括操作系统本身的代码和应用程序代码,所面对的地址空间都是线性地址空间(虚拟地址),这种做法相当于屏蔽了处理器中的逻辑地址概念,段只被用于访问控制和内存保护。

Linux 内存管理 | 地址映射:分段、分页、段页相关推荐

  1. Linux内存管理之一 分段与分页

    Linux内存管理之一 分段与分页 Posted on 2012-07-19 21:22 sin 阅读(3130) 评论(0)  编辑 收藏 引用 所属分类: Linux编程 现代操作系统的内存管理机 ...

  2. linux 内存管理 Transparent HugePages 透明大页 简介

    1. 介绍 从RedHat6, RedHat7, OL6, OL7 SLES11 and UEK2 kernels开始,透明大页默认是被开启的以便去改善操作系统的内存管理.透明大页与之前版本的传统意义 ...

  3. linux内存管理(八)-不连续页分配和页表

    一.不连续页 1.不连续页的接口函数 a.用户台接口函数 //分配不连续的物理页并且把物理页映射到连续的虚拟地址空间: void *vmalloc(unsigned long size);//释放vm ...

  4. 12 操作系统第三章 内存管理 非连续分配管理方式 基本分页存储管理 基本分段存储管理 段页式存储管理

    文章目录 1 基本分页存储管理 1.1 什么是分页存储 1.2 重要的数据结构--页表 1.3 基本地址变换机构 1.4 具有快表的地址变换机构 1.4.1 什么是快表(TLB) 1.4.2 引入快表 ...

  5. linux 内存 段,Linux内存储器管理之分段机制

    Linux内存管理之分段机制 逻辑地址就是我们普通的段+偏移的表现方式,而线性地址就是段+偏移之后算出来的一个地址,前者可以认 为是二维的地址,而后者可以理解是一维的.线性地址和虚拟地址的概念相接近, ...

  6. linux 内存管理 ppt,Linux内存管理 Memory Manager.ppt

    <Linux内存管理 Memory Manager.ppt>由会员分享,可在线阅读,更多相关<Linux内存管理 Memory Manager.ppt(24页珍藏版)>请在人人 ...

  7. Linux内存管理:内存寻址之分段机制与分页机制

    目录 Linux 内存寻址之分段机制 前言 分段到底是怎么回事? 实模式的诞生(16位处理器及寻址) 保护模式的诞生(32位处理器及寻址) IA32的内存寻址机制 寻址硬件 IA32的三种地址 MMU ...

  8. linux内存段页,linux内存管理-段式和页式管理

    该博文参考国嵌视频和http://www.cnblogs.com/image-eye/archive/2011/07/13/2105765.html,在此感谢作者. 一.地址类型 物理地址:CPU通过 ...

  9. Linux内存管理:分页机制

    <Linux内存管理:内存描述之内存节点node> <Linux内存管理:内存描述之内存区域zone> <Linux内存管理:内存描述之内存页面page> < ...

最新文章

  1. 【javascript系列】字符串:字符串单个字符访问
  2. IDEA解决SSM项目的静态资源路径问题:HTML,CSS,JS--详解
  3. a站手机访问电脑版_公司电脑一键变网盘,支持手机、家里电脑远程访问
  4. Docker中部署mysql数据库
  5. FormView在什么情况下自动生成模板项?
  6. MySQL 事务(Transaction)篇
  7. spring获取webapplicationcontext,applicationcontext几
  8. python对于设计师有什么用-Python前程无忧深圳UI设计师岗位分析
  9. python 判断 字串包含_Python变量
  10. 弹出窗口背景透明 css,CSS弹出背景半透明窗口
  11. 基于python实现网络课程秒刷
  12. 新概念下兴起域名商机 云域名是神马浮云
  13. python编程最大值_python求最大值最小值方法总结
  14. 翻译《有关编程、重构及其他的终极问题?》——13.表格化的格式化
  15. 2020考研计算机(408)考试大纲
  16. 「镁客·请讲」打造一台眼睛专属“跑步机”,鹰视菲诺是如何用AI拯救近视的?...
  17. JZOJ 1266. 玉米田
  18. 计算机图形学(1)基本图形算法
  19. uptime 之一 /proc/uptime
  20. 【XR-3】小道消息 (Comet OJ - Contest #9 X Round 3 )

热门文章

  1. 文件操作-读取文件内容
  2. 制作bpmn html,BPMN 2.0规范详解
  3. 对计算机的理解大一1000,大一计算机实训报告总结范文-求计算机实习报告1000字左右,急急急?...
  4. flyme禁止系统更新_魅族Flyme更新8.1.2.3A:重要系统更新!
  5. 多重循环控制(难点重点)
  6. 【Linux笔记】第七篇、配置MariaDB的字符集
  7. linux常用命令和选项
  8. MAC 压测工具Webbench
  9. hdoj1428 -- 漫步校园 (记忆化搜索)
  10. 删除vss文件批处理