系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理

系统,内存,管理,虚拟内存,分段,分页,页表,缓存,tlb,以及,linux · 浏览次数 : 591

小编点评

**虚拟内存虚拟内存** **什么是虚拟内存?** 虚拟内存是一种操作系统提供的机制,用于将每个进程分配的独立的虚拟地址空间映射到实际的物理内存地址空间上。 **虚拟内存的使用方式** 1. 程序访问虚拟地址。 2. 操作系统通过段选择子从段表中找到对应的段描述符。 3. 根据段描述符,操作系统选择相应的物理内存区域来存储页面数据。 4. 页面数据被分页存储,多个页面放在同一个物理内存单元中。 **虚拟内存的优点** * 解决了多个应用程序直接操作物理内存可能引发的冲突问题。 * 每个进程可以拥有相同的虚拟地址空间,避免地址冲突。 * 降低了内存访问的成本。 **虚拟内存的缺点** * 分段和分页机制可能增加了虚拟内存访问的成本。 * 如果虚拟地址空间过大,虚拟内存访问效率可能下降。 **分页机制** 分页机制是一种常用的虚拟内存访问技术,它将虚拟地址空间分成多个分页,每个分页存储了相同数量的页面数据。 *一级页表包含 1024 个页表项。 * 二级分页包含 1024 个一级页表。 * 一级页表覆盖整个虚拟地址空间。 **页表缓存** 页表缓存是一个位于 CPU 中的缓存,用于存储程序中最常访问的页表项。 **结论** 虚拟内存是操作系统提供的一种机制,通过将每个进程分配的独立的虚拟地址空间映射到实际的物理内存地址空间上,解决了多个应用程序直接操作物理内存可能引发的冲突问题。分页机制是虚拟内存访问技术中常用的一种。

正文

虚拟内存

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

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

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

image

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

内存分段

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

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

具体的映射过程如下:

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

image

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

image

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

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

内存分页

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

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

image

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

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

image

简单分页

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

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

多级页表

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

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

image

换个角度来看,大多数程序未使用到整个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内存管理

image

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

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

image

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

总结

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

与系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理相似的内容:

系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理

虚拟内存的主要作用是提供更大的地址空间,使得每个进程都可以拥有大量的虚拟内存,而不受物理内存大小的限制。此外,虚拟内存还可以提供内存保护和共享的机制,保护每个进程的内存空间不被其他进程非法访问,并允许多个进程共享同一份物理内存数据,提高了系统的资源利用率。虚拟内存的实现方式有分段和分页两种,其中分页机制更为常用和灵活。分页机制将虚拟内存划分为固定大小的页,将每个进程的虚拟地址空间映射到物理内存的页

【操作系统】内存管理概述

目录内存管理硬件结构早期内存的使用方法分段分页逻辑地址,线性地址(intel架构)虚拟地址物理地址结构图虚拟地址到物理地址的转换内存管理总览系统调用vm_area_struct缺页中断伙伴系统slab分配器页面回收反向映射KSMhuge page页迁移内存规整OOM内存管理的一些数据结构线性映射st

[转帖]Linux系统:page fault

Linux进程如何访问内存 Linux下,进程并不是直接访问物理内存,而是通过内存管理单元(MMU)来访问内存资源,原因后面会讲到。 为什么需要虚拟内存地址空间 假设某个进程需要4MB的空间,内存假设是1MB的,如果进程直接使用物理地址,这个进程会因为内存不足跑不起来。既然进程不是直接访问物理内存,

[转帖]配置大页内存实施方案

https://tool.4xseo.com/article/35670.html 如果系统性能稳定无异常,则不需要大的页面内存。HugePages_Free等于HugePages _ Total ... 展开 一、概述HugePages是通过使用大页内存来取代传统的4kb内存页面,使得管理虚拟地址

一篇教程搞定Windows系统中的Docker应用安装

Docker是一个用于创建、管理和编排容器的应用。容器是运行在操作系统上的一个应用,具有规模小、轻量化的特性。相对于虚拟机技术,容器可以为我们节省大量的系统资源,也正因此,容器可以轻松地在裸机系统以及多种云服务环境中移动。由于Docker是依赖Linux内核的应用,在Linux系统和MacOS系统中...

[转帖]操作系统-内存管理

https://www.cnblogs.com/xiaojiesir/p/15306613.html 内存管理 所有用户进程和系统所需要的全部程序和数据不可能都放入到主存中,操作系统将内存空间进行合理的划分和有效地动态分配,这就是内存管理。 内存管理主要需要满足的需求包括;重定位、保护、共享、逻辑组

[转帖]内存管理干货推荐:巨页HugePage

https://zhuanlan.zhihu.com/p/542132384 前言: 巨页的提出初衷是提供对内存使用量大的进程在某些场合下能拥有更好的性能的一种策略。巨页的定义有些含糊,按照最初提出patchset的人的意思,只要大于系统默认PAGE_SIZE的页,都可以称之为巨页。巨页从2.6发展

【内存管理】页面分配机制

前言 Linux内核中是如何分配出页面的,如果我们站在CPU的角度去看这个问题,CPU能分配出来的页面是以物理页面为单位的。也就是我们计算机中常讲的分页机制。本文就看下Linux内核是如何管理,释放和分配这些物理页面的。 伙伴算法 伙伴系统的定义 大家都知道,Linux内核的页面分配器的基本算法是基

4.2 C++ Boost 内存池管理库

Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量、可移植、高效的C应用程序。Boost库可以作为标准C库的后备,通常被称为准标准库,是C标准化进程的重要开发引擎之一。使用Boost库可以加速C应用程序的开发过程,提高代码质量和性能,并且可以适用于多种不同的系统平台和编译器。Boost库已被广泛应用于许多不同领域的C++应用程序

操作系统中的重要角色--内存管理

在开发工作中,虽然CPU,内存和硬盘都是必不可少的硬件,不过,编程中,我们常常受到困扰的往往是内存相关的bug(编程中遇到CPU和硬盘相关的bug极少)。 这是因为我们的程序和数据虽然是存放在硬盘上的,但是运行时,CPU并不是直接从硬盘加载程序和数据的。直接从硬盘读取指令非常慢,会成为整个系统的严重