当前位置: 首页 > news >正文

Linux之内存管理前世今生(一)

一个程序(如王者荣耀)平常是存储在硬盘上的,运行时才把这个程序载入内存,CPU才能执行。

问题:
这个程序载入内存的哪个位置呢?载入内核所在的空间吗?系统直接挂了。

一、虚拟内存

1.1 内存分段管理

最早的程序员写代码时是需要指定程序在内存的运行位置的,也即他们使用绝对地址来进行内存访问的。

  • 计算机刚启动时采用实模式运行,即使用绝对地址来进行内存访问;
  • 操作系统加载完成会变成保护模式,即使用虚拟地址进行内存访问。

问题来了:

  • 在有限的物理内存空间内,多道程序是无法并行运行的,举个栗子:王者荣耀需要在内存地址0x0000 ~ 0x6000上,微信需要在内存地址 0x0000 ~ 0x3000,这下好了,谁也跑不起来,直接崩了;
  • 程序员需要关注自己写的程序要跑在多大的物理内存上,内存地址怎么分配……这耦合性也太高了,而且不安全,容易访问到其他程序已使用的物理内存。

解决方法很简单:所有程序无需关心内存物理地址,代码经过编译,链接看到的地址都一样,从 0 开始到最大地址的空间,这个地址空间是独立的,是该程序私有的,其它程序既看不到,也不能访问该地址空间,这个地址空间和其它程序无关,记为虚拟内存(Virtual memory) ,虚拟内存地址记为虚拟地址,物理内存的地址记为物理地址

  • 程序运行时找一块空闲物理内存装入即可。比如之前例子:

    • 王者荣耀(虚拟地址0x0000 ~ 0x6000)运行在物理内存0x0000 ~ 0x6000;
    • 微信(虚拟地址0x0000 ~ 0x3000)运行在0x6000 ~ 0x9000;
  • 上述分配意味着我们需要记录虚拟空间和物理空间的映射关系:我们将这个表记为段表,因为映射的一段完整连续的物理内存。

    进程虚拟地址物理地址
    王者荣耀0x0000 ~ 0x60000x0000 ~ 0x6000
    微信0x0000 ~ 0x30000x6000 ~ 0x9000
  • 段表实际记录的是段的基址和边界,使用时通过段表找到物理内存地址,再结合段内偏移量即可定位数据。

在这里插入图片描述

上述为内存分段管理大致原理,实际内存分段管理和早期硬件发展相关,分为几个大的段,同时配合段寄存器使用。

cs: 代码段
ds: 数据段
ss: 栈段
es:扩展段

1.2 内存分页管理

前面我们成功的让2个程序同时正确的跑起来了,但是物理内存是有限的,如之前所示最大地址为0xA000,现在想听网易云音乐(虚拟地址为 0x0000 ~ 0x4000),这就尴尬了,空闲的物理内存(0x9000 ~ 0xA000)不够支持网易云音乐了,但现实中,我们上述需求的确可以同时满足啊?

  • 上述无法使用的内存空间(0x9000 ~ 0xA000),称为内存外部碎片;即分段管理存在明显的外部碎片;
  • 相对应的,已分配过程序内存内部存在没有使用到的空间称为内存内部碎片

其实也很简单,我们把程序分批次装入物理内存中,每次只载入一部分来满足运行即可,我们把这部分程序内容记为 page (页),存放页的物理内存区域记为page frame (页框)

  • 管理内存的最小单位是页;
  • 分页管理没有外部碎片了,每一个页框均可使用。

实际当中每次载入多少数据合适呢?一般为 4KB,即 页的大小为4KB,页框的大小也为 4KB。将物理内存和虚拟内存按照的大小(4KB) 分割,需要哪页就加载那页内容,找一个空闲的页框存放即可。这样我们在有限的物理内存内,载入并正确并行了多道程序。

在这里插入图片描述

按照上述策略,我们成功得将3个程序并行跑起来了,如下图所示:

在这里插入图片描述

1.2.1 页表

虚拟内存页和物理内存页的映射关系也得占用物理内存进行存储,即上图所示的 页表,一个页表也占用一个页框存储,即一个页表最大为 4KB。下图即为页表图示,观察下图,虚拟页号就是下标,所以页表可以用一个一维数组存储即可:数组下标为虚拟页号,数组内容为物理页号和物理内存起始地址等其它额外信息:

在这里插入图片描述

页面大小为4kByte,因此每个页框的低12位均为0。内核将低12位充分利用,每个位都表示对应虚拟页的相关属性。同样的骚操作在64位JVM中指针压缩也有。

1.2.2 物理地址计算

给定虚拟地址 0x0809 怎么计算物理地址呢?

  1. 根据虚拟地址和页大小(4KB,按Byte编址需要 12 个 bit )计算虚拟页号,和页内偏移量;
    • 虚拟页号: 0(0x0809 / 4k );
    • 页内偏移量: 9(0x0800 % 4k);
  2. 页表基址寄存器找到页表物理地址;
  3. 查页表找到物理页号;
  4. 根据物理页号起始地址和页内偏移量得到物理地址。
    在这里插入图片描述

计算机中完成上述地址转换的部件由特定硬件完成,叫做 MMU(Memory Management Unit,内存管理单元),它位于CPU 芯片中。

1.2.3 缺页中断

因为我们只将程序部分页面载入到内存当中,当运行完这些页面继续往后运行时,进程访问的虚拟地址在页表中查不到时,即后续页面还在磁盘上,此时 MMU 会触发缺页中断(page fault),从磁盘上将对应页面加载到物理内存中空闲页框内,同时更新页表。

1.2.4 多级页表

在 32 位的环境下,每个进程的虚拟内存为4GB,一个页表最大为4KB,页内偏移量12 bit,剩余 20bit (32-12) 用于页号,可以表示约 1,000,000(220)页, 页表中每一项(记为页表项)需要 4Byte,所以4GB空间需要4MB(220 * 4Byte)物理内存来存储页表。

这意味着,如果计算机并行10个进程的话需要 40MB 内存,实际中开启的进程远不止10个,需要更大内存来存储页表。

所以不可能将页表(4MB)全部放进内存,又必须能看到页表全貌,怎么办?
兵仙韩信说,只需十个将军,即可统帅百万大军;
同理,只需一个页表索引(页目录),即可查找百万页表项,即:
一页可以放1024(4KB / 4Byte)个页索引,二级可以存储即可表示 220(1024 * 1024)页,刚好覆盖整个 4GB (4KB * 220 )虚拟地址空间。

在这里插入图片描述

  • 使用时通过一级页表(记为页目录),找到二级页表,从而得到最终物理地址;
  • 若二级页表不存在,触发缺页中断进行加载即可;
  • 这不是一颗B树吗?树高2。
1.2.4.1 多级页表物理地址
  • 在 32 位的环境下,我们将虚拟地址原页号进行分割,10bit 存放一级页号(页目录),10bit 存放二级页号(页表项),如下图所示:
  • 在 64 位的环境下,二级分页是无法满足的,实际使用时分为四级索引,即B树高度为4;
    • 四级索引前面3级为页目录,叶子节点为页表,依次命名为:
      • 全局页目录项 PGD(Page Global Directory)
      • 上层页目录项 PUD(Page Upper Directory)
      • 中间页目录项 PMD(Page Middle Directory)
      • 页表项 PTE(Page Table Entry)
    • 页表项为 8Byte,一页(4KB)可以索引 512 (4KB / 8Byte) 个页;
    • 四级可以索引 5124 个页,可以表示 256TB (4KB * 5124) 虚拟空间;
    • 512 个页号使用 9 (29 = 512)个 bit就可以表示;
    • 四级页表使用 36(4 * 9)个bit可以表示;
    • 64 位环境用 48(36 + 12)个bit 进行寻址(意味着PGD中 高位 16 bit 全0或者全1),表示 256TB 空间

在这里插入图片描述

小节:虚拟地址本质上是索引+偏移量

1.2.5 页表缓存TLB(Translation Lookaside Buffer)

计算机中为协调CPU和内存的访问速度(一次内存的访问,大约需要 120 个 CPU Cycle),中间加了 高速缓存(CPU Cache)

  • 高速缓存使用特定的由 SRAM (静态RAM (random-access memory,随机访问存储器)) 组成的物理芯片,内存使用DRAM(动态RAM);
  • 高速缓存为3级:L1/L2/L3 Cache。其中 L1/L2 是 CPU 私有,L3 是所有 CPU 共享。
  • 缓存行(Cache Line):高速缓存的最小单元,一次从内存中读取的数据大小。常用的 Intel 服务器 Cache Line 的大小通常是 64 字节。
  • CPU Cache 的命中率通常能达到 95% 以上。

我们前面提到的 页表项(PTE) 同样需要从内存加载到高速缓存来提高CPU访问速度,由于高速缓存空间远小于内存空间,所以只能缓存程序中最常访问的页表项,我们把缓存页表项的这块区域称为转址旁路缓存(TLB,Translation Lookaside Buffer),也称为快表(内存中的表相应为慢表)。

在这里插入图片描述

1.3 内存段页式管理

内存管理最开始分段管理,后面又提出分页管理,由于硬件和版本限制,现在操作系统中的内存管理理论上是由段页结合一起管理的,即先分段,然后段内分页。
实际使用时,操作系统做了简化,将代码段和数据段的基址设为0,段空间大小为这个虚拟内存的大小。
即现代操作系统中,分段管理名存实亡。

在这里插入图片描述

在 CPU 中,程序使用逻辑内存地址;

1.4 虚拟内存空间整体布局

虚拟内存空间并非全部留给程序,一般而言高地址段为内核空间,用于系统内核使用,低地址段为用户空间,留给程序使用,如下图所示:

在这里插入图片描述

1.4.1 用户态虚拟内存

程序是由源代码经过编译、链接形成的可执行文件(ELF)。ELF中分为代码段(.text)、数据段(.data)、未初始化数据段(.bss)等很多逻辑段,虚拟内存为保持这种程序的逻辑性,同样也在逻辑上将内存划分为代码段、数据段、堆、文件映射与匿名映射区、栈等。

在这里插入图片描述

注意

  • 一个段(segment)一般包含多个页(page),每个段的长度并不相等;
  • 保留区这段虚拟内存是不可访问的,因为在大多数操作系统中,数值比较小的地址通常被认为不是一个合法的地址,这块小地址是不允许访问的。比如在 C 语言中我们通常会将一些无效的指针设置为 NULL,指向这块不允许访问的地址。
  • 文件映射区使用时均是从高地址向低地址分配
  • 使用时从低地址向高地址分配
  • 不可访问段仅存在于64位环境中,为了防止程序在读写数据段的时候越界访问到代码段,这个保护段可以让越界访问行为直接崩溃,防止它继续往下运行。
  • 通过 cat /proc/pid/maps 或者 pmap pid 查看进程的虚拟内存空间布局以及其中包含的所有内存区域。
  • 进程进入内核态之后使用的仍然是虚拟内存地址,只不过在内核中使用的虚拟内存地址被限制在了内核态虚拟内存空间范围中。

虚拟内存的内容暂时介绍到这里,后续会介绍物理内存的实际分配情况。

相关文章:

Linux之内存管理前世今生(一)

一个程序(如王者荣耀)平常是存储在硬盘上的,运行时才把这个程序载入内存,CPU才能执行。 问题: 这个程序载入内存的哪个位置呢?载入内核所在的空间吗?系统直接挂了。 一、虚拟内存 1.1 内存分…...

Beautiful Soup 入门指南:从零开始掌握网页解析

Beautiful Soup 入门指南:从零开始掌握网页解析 前言 在数据驱动的时代,网页数据是非常宝贵的资源。很多时候我们需要从网页上提取数据,进行分析和处理。Beautiful Soup 是一个非常流行的 Python 库,可以帮助我们轻松地解析和提…...

网络通信---MCU移植LWIP

使用的MCU型号为STM32F429IGT6,PHY为LAN7820A 目标是通过MCU的ETH给LWIP提供输入输出从而实现基本的Ping应答 OK废话不多说我们直接开始 下载源码 LWIP包源码:lwip源码 -在这里下载 ST官方支持的ETH包:ST-ETH支持包 这里下载 创建工程 …...

Go-并行编程新手指南

Go 并行编程新手指南 在Go语言中,并行编程是充分利用多核CPU资源、提升程序性能的重要手段。它的核心概念包括goroutine和channel,这些特性使得Go在处理并发任务时表现出色。 goroutine:轻量级的并发执行单元 goroutine是Go并行编程的基础…...

基于Django的个人博客系统的设计与实现

【Django】基于Django的个人博客系统的设计与实现(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 系统采用Python作为主要开发语言,结合Django框架构建后端逻辑,并运用J…...

Python爬虫获取custom-1688自定义API操作接口

一、引言 在电子商务领域,1688作为国内领先的B2B平台,提供了丰富的API接口,允许开发者获取商品信息、店铺信息等。其中,custom接口允许开发者进行自定义操作,获取特定的数据。本文将详细介绍如何使用Python调用1688的…...

kaggle-ISIC 2024 - 使用 3D-TBP 检测皮肤癌-学习笔记

问题描述: 通过从 3D 全身照片 (TBP) 中裁剪出单个病变来识别经组织学确诊的皮肤癌病例 数据集描述: 图像临床文本信息 评价指标: pAUC,用于保证敏感性高于指定阈值下的AUC 主流方法分析(文本) 基于CatBoo…...

滤波电路汇总

0、前言 1. 引言 滤波电路是电子系统中不可或缺的组成部分,其主要功能是选择性地通过或衰减特定频率范围内的信号。在现代电子技术中,滤波电路广泛应用于信号处理、通信系统、音频设备、电源设计等多个领域。通过滤波,可以去除信号中的噪声和干扰,提高信号的质量和稳定性…...

1.Template Method 模式

模式定义 定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method 使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特…...

MySQL分表自动化创建的实现方案(存储过程、事件调度器)

《MySQL 新年度自动分表创建项目方案》 一、项目目的 在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低。分表是一种有效的优化策略,它将数据分散存储在多…...

基于回归分析法的光伏发电系统最大功率计算simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 5.完整工程文件 1.课题概述 基于回归分析法的光伏发电系统最大功率计算simulink建模与仿真。选择回归法进行最大功率点的追踪,使用光强和温度作为影响因素,电压作为输出进行建模。…...

计算机毕业设计【任务书】怎么写?

1. 什么是毕业设计任务书 毕业设计任务书是学生在毕业设计初期向指导教师提交的文档,主要用于说明毕业设计的选题、研究内容、目标、方法、进度安排等。 2. 撰写任务书的步骤 2.1 确定选题 选题是撰写任务书的第一步。选题应结合自身兴趣、专业方向和实际应用需…...

GRAPHARG——学习

20250106 项目git地址:https://github.com/microsoft/graphrag.git 版本:1.2.0 ### This config file contains required core defaults that must be set, along with a handful of common optional settings. ### For a full list of available setti…...

【Rust自学】15.6. RefCell与内部可变性:“摆脱”安全性限制

题外话,这篇文章一共4050字,是截止到目前为止最长的文章,如果你能坚持读完并理解,那真的很强! 喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以…...

14.模型,纹理,着色器

模型、纹理和着色器是计算机图形学中的三个核心概念,用通俗易懂的方式来解释: 1. 模型:3D物体的骨架 通俗解释: 模型就像3D物体的骨架,定义了物体的形状和结构。 比如,一个房子的模型包括墙、屋顶、窗户等…...

【C语言分支与循环结构详解】

目录 ---------------------------------------begin--------------------------------------- 一、分支结构 1. if语句 2. switch语句 二、循环结构 1. for循环 2. while循环 3. do-while循环 三、嵌套结构 结语 -----------------------------------------end----…...

新项目上传gitlab

Git global setup git config --global user.name “FUFANGYU” git config --global user.email “fyfucnic.cn” Create a new repository git clone gitgit.dev.arp.cn:casDs/sawrd.git cd sawrd touch README.md git add README.md git commit -m “add README” git push…...

qt-QtQuick笔记之常见项目类简要介绍

qt-QtQuick笔记之常见项目类简要介绍 code review! 文章目录 qt-QtQuick笔记之常见项目类简要介绍1.QQuickItem2.QQuickRectangle3.QQuickImage4.QQuickText5.QQuickBorderImage6.QQuickTextInput7.QQuickButton8.QQuickSwitch9.QQuickListView10.QQuickGridView11.QQuickPopu…...

Continuous Batching 连续批处理

原始论文题目: Continuous Batching — ORCA: a distributed serving system for Transformer-based generative models 关键词: Continuous Batching, iteration-level scheduling, selective batching 1.迭代级调度(iteration-level scheduling) Orca系统又由几个关键…...

海外问卷调查渠道查如何设置:最佳实践+示例

随着经济全球化和一体化进程的加速,企业间的竞争日益加剧,为了获得更大的市场份额,对企业和品牌而言,了解受众群体的的需求、偏好和痛点才是走向成功的关键。而海外问卷调查才是获得受众群体痛点的关键,制作海外问卷调…...

把本地搭建的hexo博客部署到自己的服务器上

配置远程服务器的git 安装git 安装依赖工具包 yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel安装编译工具 yum install -y gcc perl-ExtUtils-MakeMaker package下载git,也可以去官网下载了传到服务器上 wget https://www.ke…...

初阶数据结构:链表(二)

目录 一、前言 二、带头双向循环链表 1.带头双向循环链表的结构 (1)什么是带头? (2)什么是双向呢? (3)那什么是循环呢? 2.带头双向循环链表的实现 (1)节点结构 (2…...

postgresql根据主键ID字段分批删除表数据

生产环境针对大表的处理相对比较麻烦。 方案1、直接truncate,可能会遇到系统卡主的情况,因为truncate的过程中会对表进行加锁,会导致数据不能正常的写入 方案2、创建一个同结构的表结构,rename旧表,不停业务rename表担…...

10.business english-global market

eco-friendly case study: 案例学习 At the workshop工作坊, they agreed to emphasize eco-friendliness,adapt messageing, and boost digital marketing to stand out globally. Our study shows that more people want eco-friendly products in different places.Looks …...

C 语言实现计算一年中指定日期是第几天 题】

引言 在编程的世界里,处理日期和时间相关的问题是非常常见的。比如在日历应用、任务管理系统、数据分析等场景中,经常需要计算某个日期在一年中是第几天。本文将详细介绍如何使用 C 语言来实现这一功能,通过分析代码的结构、逻辑以及可能存在…...

深入理解三高架构:高可用性、高性能、高扩展性的最佳实践

引言 在现代互联网环境下,随着用户规模和业务需求的快速增长,系统架构的设计变得尤为重要。为了确保系统能够在高负载和复杂场景下稳定运行,"三高架构"(高可用性、高性能、高扩展性)成为技术架构设计中的核…...

【反悔堆】力扣1642. 可以到达的最远建筑

给你一个整数数组 heights ,表示建筑物的高度。另有一些砖块 bricks 和梯子 ladders 。 你从建筑物 0 开始旅程,不断向后面的建筑物移动,期间可能会用到砖块或梯子。 当从建筑物 i 移动到建筑物 i1(下标 从 0 开始 )…...

关于使用Mybatis-plus的TableNameHandler动态表名处理器实现分表业务的详细介绍

引言 随着互联网应用的快速发展,数据量呈爆炸式增长。传统的单表设计在面对海量数据时显得力不从心,容易出现性能瓶颈、查询效率低下等问题。为了提高数据库的扩展性和响应速度,分表(Sharding)成为了一种常见的解决方案…...

docker 安装 redis 详解

在平常的开发工作中,我们经常会用到 redis,那么 docker 下应该如何安装 redis 呢?简单来说:第一步:拉取redis镜像;第二步:设置 redis.conf 配置文件;第三步:编写 docker-…...

56. 合并区间

【题目】&#xff1a;56. 合并区间 class Solution { public:vector<vector<int>> merge(vector<vector<int>>& intervals) {// 按照左端点排序sort(intervals.begin(), intervals.end(), [&](vector<int> lhs, vector<int> rhs)…...