虚拟内存

虚拟内存是一种操作系统提供的机制,用于将每个进程分配的独立的虚拟地址空间映射到实际的物理内存地址空间上。通过使用虚拟内存,操作系统可以有效地解决多个应用程序直接操作物理内存可能引发的冲突问题。

在使用虚拟内存的情况下,每个进程都有自己的独立的虚拟地址空间,它们不能直接访问物理内存地址。当程序访问虚拟内存地址时,操作系统会进行地址转换,将虚拟地址映射到物理地址上,这样不同的进程运行时,写入的是不同的物理地址,避免了互相覆盖指针的问题。

虚拟内存的使用使得每个进程都可以拥有相同的虚拟地址空间,而不用担心与其他进程的地址冲突。操作系统负责管理虚拟地址和物理地址之间的映射关系,并在需要时进行地址转换。这样,进程可以以一种透明的方式访问内存,无需关心内存的实际物理位置。

通过虚拟内存机制,操作系统能够更好地管理系统内存资源,提供更高的安全性和稳定性。它可以为每个进程提供独立的地址空间,保护进程间的数据隔离,同时也可以有效地利用物理内存,将不常用的数据交换到磁盘上(交换区),以提供更大的可用内存空间。

内存分段

在分段机制下,虚拟地址由两部分组成:段选择子和段内偏移量。段选择子是一个索引,用于指定要访问的段的起始地址和长度。段内偏移量则表示在该段内的具体位置。

操作系统会维护一个段表,其中包含了每个段的起始地址和长度信息。当程序访问一个虚拟地址时,操作系统会通过段选择子从段表中找到对应的段描述符,然后根据段描述符中的信息计算出物理地址。

具体的映射过程如下:

  1. 程序访问虚拟地址,通过段选择子找到对应的段描述符。
  2. 根据段描述符中的基址和长度信息,计算出段的起始物理地址。
  3. 将段的起始物理地址与段内偏移量相加,得到最终的物理地址。

不过,需要注意的是,分段机制可能会导致内存碎片的问题,因为不同段的大小可能不同,导致一些碎片化的空间无法被利用。当不够内存分配的时候,会选择使用内存交换,先把一块正在使用的内存移到磁盘中,然后再移回来把中间留的内存缝隙全用上,虽然解决了内存碎片的问题,但是这个交换操作很慢,效率低,看下图示:

虚拟内存、分段和内存交换似乎解决了同时运行多个程序的问题,但仍存在性能瓶颈。由于硬盘访问速度较慢,每次内存交换都需要将大段连续的内存数据写入硬盘。因此,如果交换的是占用大量内存空间的程序,整个系统会变得卡顿。

为了解决内存分段的碎片和提高内存交换效率,引入了内存分页机制。

内存分页

内存分页是将整个虚拟和物理内存空间划分为固定大小的连续内存块,称为页(Page)。在Linux下,每一页的大小通常为4KB。虚拟地址与物理地址之间通过页表进行映射,页表存储在CPU的内存管理单元(MMU)中,从而CPU可以直接通过MMU找到实际访问的物理内存地址。

虚拟地址与物理地址之间通过页表来映射,如下图:

由于内存空间事先划分为固定大小的页,不会像分段机制那样产生碎片。当释放内存时,以页为单位进行释放,避免了无法利用的小内存块。

如果内存空间不足,操作系统会将其他正在运行的进程中的"最近未使用"的内存页面暂时存储到硬盘上,称为换出(Swap Out)。当需要时,再将页面加载回内存,称为换入(Swap In)。因此,每次写入硬盘的是少量的一页或几页,不会花费太多时间,从而提高了内存交换的效率。

简单分页

简单分页存在空间上的缺陷。在操作系统可以同时运行大量进程的情况下,页表会变得非常庞大。在32位环境下,虚拟地址空间为4GB,假设页的大小为4KB,就需要大约100万个页。每个页表项需要4字节来存储,所以整个4GB空间的映射需要4MB的内存来存储页表。

尽管4MB的页表看起来并不算太大,但要注意每个进程都有自己的虚拟地址空间,也就是说每个进程都有自己的页表。如果有100个进程,就需要400MB的内存来存储页表,这对于内存来说是相当大的开销,更不用说64位环境下了。

多级页表

要解决上述问题,我们可以采用一种叫做多级页表(Multi-Level Page Table)的解决方案。在之前我们已经了解到,在32位环境下,页大小为4KB的情况下,一个进程的页表需要存储100多万个页表项,每个项占用4字节的空间,因此一个页表需要4MB的内存空间。

为了节省内存空间,我们可以将单级页表进行分页,将一个页表(一级页表)分为1024个页表(二级页表),每个二级页表包含1024个页表项,形成二级分页结构。这样一级页表覆盖整个4GB的虚拟地址空间,而对于未使用的页表项,不会创建对应的二级页表,只在需要时才创建。如下图所示:

换个角度来看,大多数程序未使用到整个4GB的虚拟地址空间,因此部分页表项是空的,没有分配实际的内存空间。在物理内存紧张的情况下,操作系统会将最近一段时间未访问的页表换出到硬盘,从而释放物理内存。使用二级分页,一级页表只需要覆盖整个4GB的虚拟地址空间,而未使用的页表项不需要创建对应的二级页表。假设只有20%的一级页表项被使用,那么页表占用的内存空间只有0.804MB,相比于单级页表的4MB,内存节约非常巨大。

为什么不分级的页表无法实现这样的内存节约呢?从页表的性质来看,页表保存在内存中,其主要作用是将虚拟地址翻译为物理地址。如果在页表中找不到对应的页表项,计算机系统将无法正常工作。因此,页表必须覆盖整个虚拟地址空间。而不分级的页表需要100多万个页表项进行映射,而二级分页只需要1024个页表项(一级页表覆盖整个虚拟地址空间,二级页表在需要时创建)。

页表缓存TLB(Translation Lookaside Buffer)

TLB(Translation Lookaside Buffer)是一个位于CPU芯片中的缓存,用于存储程序中最常访问的页表项,以加快虚拟地址到物理地址的转换速度。多级页表虽然解决了空间上的问题,但是增加了转换的工序,导致时间上的开销。然而,由于程序的局部性原理,程序执行期间通常仅限于某一部分,访问的存储空间也局限于某个内存区域。因此,通过将最常访问的页表项存储到TLB这个硬件缓存中,可以更快地进行地址转换。

在CPU芯片中,内存管理单元(Memory Management Unit)芯片负责处理地址转换和TLB的访问与交互。当CPU进行寻址时,首先会查找TLB,如果找到了对应的页表项,就可以直接进行物理地址的访问,避免了继续查找常规页表的开销。

由于TLB中存储的是程序最常访问的几个页表项,所以TLB的命中率通常是很高的。这是因为程序执行过程中,访问的页表项相对固定。通过利用TLB,可以大大提高地址转换的速度,加快程序的执行效率。

Linux内存管理

Linux内存管理涉及逻辑地址和线性地址的转换。逻辑地址是程序使用的地址,而线性地址是通过段式内存管理映射的地址,也称为虚拟地址。

Linux的虚拟地址空间分为内核空间和用户空间两部分。32位系统中,内核空间占用1G,剩下的3G是用户空间;64位系统中,内核空间和用户空间都是128T,分别占据内存空间的最高和最低处。如下所示:

进程在用户态时只能访问用户空间内存,进入内核态后才能访问内核空间内存。虽然每个进程都有独立的虚拟内存,但虚拟内存中的内核地址关联的是相同的物理内存,这样进程切换到内核态后就可以方便地访问内核空间内存。

总结

虚拟内存是操作系统提供的一种机制,通过将每个进程分配的独立的虚拟地址空间映射到实际的物理内存地址空间上,解决了多个应用程序直接操作物理内存可能引发的冲突问题。虚拟内存的使用使得每个进程都可以拥有相同的虚拟地址空间,而不用担心与其他进程的地址冲突。通过虚拟内存机制,操作系统能够更好地管理系统内存资源,提供更高的安全性和稳定性。虚拟内存的实现方式有分段和分页,其中分页机制更为常用,采用多级页表的方式节约了内存空间。页表缓存TLB能够加快虚拟地址到物理地址的转换速度。Linux的内存管理涉及逻辑地址和线性地址的转换,将虚拟地址空间分为内核空间和用户空间,方便进程访问内核空间内存。

系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理的更多相关文章

  1. Linux内存管理解析(一) : 分段与分页机制

    背景 : 在此文章里会从分页分段机制去解析Linux内存管理系统如何工作的,由于Linux内存管理过于复杂而本人能力有限.会尽量将自己总结归纳的部分写清晰. 从实模式到保护模式的寻址方式的不同 : 1 ...

  2. Linux(3)- 用户管理、文件与目录权限、常用命令、Linux软件包管理

    一.用户管理 现代操作系统一般属于多用户的操作系统,也就是说,同一台机器可以为多个用户建立账户,一般这些用户都是为普通用户,这些普通用户能同时登录这台计算机,计算机对这些用户分配一定的资源. 普通用户 ...

  3. Linux内存寻址之分段机制及分页机制【转】

    前言 本文涉及的硬件平台是X86,如果是其他平台的话,如ARM,是会使用到MMU,但是没有使用到分段机制: 最近在学习Linux内核,读到<深入理解Linux内核>的内存寻址一章.原本以为 ...

  4. Linux内存管理 【转】

    转自:http://blog.chinaunix.net/uid-25909619-id-4491368.html Linux内存管理 摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理 ...

  5. Linux内存管理【转】

    转自:http://www.cnblogs.com/wuchanming/p/4360264.html 转载:http://www.kerneltravel.net/journal/v/mem.htm ...

  6. Linux内存管理(最透彻的一篇)【转】

    转自:https://www.cnblogs.com/ralap7/p/9184773.html 摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物 ...

  7. 【转】Linux内存管理(最透彻的一篇)

    摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法.力求从外到内.水到渠成地引导网友分析Linux的内存管理与使用.在 ...

  8. 【转帖】linux内存管理原理深入理解段式页式

    linux内存管理原理深入理解段式页式 https://blog.csdn.net/h674174380/article/details/75453750 其实一直没弄明白 linux 到底是 段页式 ...

  9. Linux内存管理—详细讲解

    摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法.力求从外到内.水到渠成地引导网友分析Linux的内存管理与使用.在 ...

  10. linux中的分段和分页

    http://blog.csdn.net/hguisu/article/details/6152921 Linux 内存管理 觉得这篇文章写分段和分页机制还是挺清晰的,在此转载一下. 前一段时间看了& ...

随机推荐

  1. vue全家桶进阶之路37:Vue3 路由守卫

    在 Vue.js 3.x 中,我们可以使用路由守卫来拦截路由的跳转,从而实现一些功能,例如:登录验证.页面权限控制等. Vue.js 3.x 中的路由守卫和 Vue.js 2.x 中的基本相同,都包含 ...

  2. Vue跨域详解

    碰到这种问题,其实你的接口已经通了,但是在页面上就是访问不通过. 你可以把API请求地址单独拎出来新开个网站打开看请求是否成功,成功,但是你的项目不通. 有那么几个可能吧: 1.请求头设置错误 hea ...

  3. Event Tables for Efficient Experience Replay

    Abstract 事件表分层抽样(SSET),它将ER缓冲区划分为事件表,每个事件表捕获最优行为的重要子序列. 我们证明了一种优于传统单片缓冲方法的理论优势,并将SSET与现有的优先采样策略相结合,以 ...

  4. 【汇编】老师太hun

    老师只是随手发实验项目卡,从未提过实验报告的事情 可是 他却要在 复习周 一下子 收6次 实验报告 也不发资料,不说每次的时间点,不讲实验 这人心中有 学生 吗? 上课发 上个班直播的录播 一节课就发 ...

  5. ES 数据没了?谁动了我的数据?

    背景 我们在使用 Elasticsearch 的时候,可能会遇到数据"丢"了的情况.有可能是数据没成功写入 ES 集群,也可能是数据被误删了. 针对数据被误删,有没有好的解决办法呢 ...

  6. web自动化04-css定位

    css元素定位 1. 是什么? 用来描述html元素的显示样式 选择器是一种模式,用于选择需要添加样式的元素   selenium中推荐使用css定位,比XPath定位要快    2.如何定位?   ...

  7. 利用jira及confluence的API进行批量操作(查找/更新/导出/备份/删除等)

    前言: 近期因为某些原因需要批量替换掉 jira 和 confluence中的特定关键字,而且在替换前还希望进行备份(以便后续恢复)和导出(方便查看)atlassian官方的api介绍文档太简陋,很多 ...

  8. 5月这几个API安全漏洞值得注意!

    5月份的一些API安全漏洞报告 希望大家查漏补缺 及时修复自己API可能出现的漏洞 No.1 微软.NET Core漏洞 漏洞详情:微软官方发布公告称,其.NET Core 2.1.3.1和5.0版本 ...

  9. 【建议收藏】Log4j配置详解

    大家在日常开发中必然会使用到日志组件,Log4j是Java方向上比较常用的日志组件,今天给大家分享下Log4j支持的配置项,强烈建议收藏,以便配置时查看 #展示log4j各种配置,私有部分见文件中注释 ...

  10. MySQL8新特性窗口函数详解

    本文博主给大家详细讲解一波 MySQL8 的新特性:窗口函数,相信大伙看完一定能有所收获. 本文提供的 sql 示例都是基于 MySQL8,由博主亲自执行确保可用 博主github地址:http:// ...