Linux内核中的内存管理剖析,干货收藏!

news2024/11/27 0:47:26

内存管理的主要工作就是对物理内存进行组织,然后对物理内存的分配和回收。但是Linux引入了虚拟地址的概念。

虚拟地址的作用

如果用户进程直接操作物理地址会有以下的坏处:

  • 用户进程可以直接操作内核对应的内存,破坏内核运行。

  • 用户进程也会破坏其他进程的运行。

CPU中寄存器中存储的是逻辑地址,需要进行映射才能转化为对应的物理地址,然后获取对应的内存。通过引入逻辑地址,每个进程都拥有单独的逻辑地址范围。

当进程申请内存的时候,会为其分配逻辑地址和物理地址,并将逻辑地址和物理地址做一个映射。所以,Linux内存管理涉及到了以下三个部分。

1.物理内存

物理内存的组织

Linux中内存分为3个级别,从下到上依次为:

1、Page:一个page的大小为4k,Page是内存的一个最基本的单位。

2、Zone:Zone中提供了多个队列来管理page。Zone分为3种:

  • ZONE_DMA:用来存放DMA读取IO设备的数据,内核专用;

  • ZONE_NORMAL:用来存放内核的相关数据,内核专用;

  • ZONE_HIGHMEM:高端内存,用来存放用户进程数据;

3、Node节点:一个CPU对应着一个Node,一个Node包括一个Zone_DMA、ZONE_NORMAL、ZONE_HIGHMEM。

同时当一个CPU对应的内存用光后,可以申请其他CPU对应的内存。

物理内存的分配
Linux将内存分配分为两种:
1、大内存:大内存利用伙伴系统分配

伙伴系统的做法是将ZONE中的Page分组,然后组装为多个链表。链表中存放的是页块的集合。页块对应着有不同的大小,分别为1、2、4、8…1024个页。

当请求(2i-1,2i]大小的page的时候,会直接请求2i个页, 如果对应的链表中有对应的页块,就直接分配。如果对应的链表没有,就往上找2i+1,如果2i+1存在,就将其分为2个2i页块,将其中1个2i加入到对应的链表中,将另外一个分配出去。

例如,要请求一个128个页的页块时,先检查128个页的页块链表是否有空闲块。如果没有,则查256个的页块链表;如果有空闲块的话,则将256个页的页块分成两份,一份使用,一份插入128个页的页块链表中。如果还是没有,就查512个页的页块链表;如果有的话,就分裂为128、128、256三个页块,一个128的使用,剩余两个插入对应页块链表。

2、小内存分配

小内存分配利用slub分配,比如对象等数据slub就是将几个页单独拎出来作为缓存,里面维护了链表。每次直接从链表中获取对应的内存,用完之后也不用清空,就直接挂到链表上,然后等待下次利用。

2.如何组织虚拟地址

虚拟地址对应的是虚拟空间,虚拟空间只不过是一个虚拟地址的集合,用来映射物理内存。

虚拟空间分为用户态和内核态。32位系统中将虚拟空间按照1:3的比例分配给内核态和用户态。64位系统中分别给内核态和用户态分配了128T。

用户态结构

每个进程都会对应一个用户态虚拟空间, 里面存放了Text(代码)的内存虚拟地址范围、Data(数据)的内存虚拟地址范围、BSS(全局变量)的内存虚拟地址范围、堆的虚拟地址范围、栈的虚拟地址范围,以及mmap内存映射区。

其中mmap用于申请动态内存的时候的映射,堆和栈都是动态变化的。

一个进程对应的用户态中的各个方面的虚拟地址信息都通过一个struct来存储在内存中,当创建进程的时候会为其分配内存存储对应的虚拟地址信息。

内核态结构

Linux的内核程序共用一个内核态虚拟空间。其中分为了以下几部分:

1、直接映射区

896M,内核空间直接映射到对应的ZONE_DMA和ZONE_NORMAL中。为什么叫做直接映射呢?逻辑地址 直接 减去对应的差值就可以得到对应的物理地址。固定死了。

2、动态映射

为什么要引入动态映射呢?因为所有物理内存的分配都需要内核程序进行申请,用户进程没有这个权限。所以内核空间一定要能映射到所有的物理内存地址。

那么如果都采用直接映射的话,1G大小逻辑地址的内核空间只能映射1G大小的物理内存。所以引入了动态映射,动态映射就是内核空间的逻辑地址可以映射到 物理内存中的ZONE_HIGHMEM(高端内存)中的任何一个地址,并且在对应的物理内存使用完之后,可以再映射其他物理内存地址。

动态映射分为三种:

  • 动态内存映射:使用完对应的物理内存后,就可以映射其他物理内存了。

  • 永久内存映射:一个虚拟地址只能映射一个物理地址。如果需要映射其他物理地址,需要解绑。

  • 固定内存映射:只能被某些特定的函数来调用引用物理地址。

动态内存映射和直接映射的区别

动态映射和直接映射的区别就是逻辑地址到物理地址的转化规则。

直接映射:直接映射的规则是死的,一个逻辑地址对应的物理地址是固定的。通过逻辑地址加或者减去一个数,就可以得到对应的物理地址。

动态映射:动态映射是动态的绑定,每个逻辑地址对应的物理地址是动态的,通过页表进行查询。

用户空间映射:用户空间采用动态映射,每个虚拟地址可以被映射到一个物理地址,映射到ZONE_HIGHMEM。

为什么用户空间不采用直接映射呢?

因为物理内存是多个进程所有的,每个进程都有一个用户空间。如果采用直接映射的话,对应的物理地址是会冲突的。其用户空间的逻辑地址大小都为3G,所以存在逻辑地址相同,但是对应的物理地址不同。需要通过页表来转化,一个进程会对应一个页表。

3.如何将虚拟地址映射到物理内存

虚拟地址通过页表将虚拟地址转化为物理地址,每个进程都对应着一个页表,内核只有一个页表。虚拟空间和物理内存都按照4k来分页,一个虚拟空间中的页和物理内存中页是一一对应的。

页表映射

如上图所示,将虚拟地址中的页号通过页表转化为对应的物理页号,然后通过页内偏移量就可以得到对应的物理地址了。

但是1个进程就需要一个页表,一个4G的内存条,就需要1M个页表记录来描述,假如1个页表记录需要4个字节,那么就需要4MB。而且页表记录是通过下标来对应的,通过虚拟页号来乘以对应的页表项大小来计算得到对应的地址的。

所以Linux将4M分为1K个4K,一个4K对应着一个page,用来存储对应的真正的页表记录。将1K个page分开存放,就不要求连续的4M了。

如果将4M分成1K个离散的page的话,怎么虚拟地址对应的页表号呢?

利用指针,存储1K个地址,分别指向这1K个page,地址的大小为4个字节,也就是32位,完全可以表示整个内存的地址范围。

1K*4个字节,正好是一个page 4k,所以也就是利用1个 page来存储对应的页表记录索引。

所以我们的虚拟地址寻找过程如下:

  • 找到对应的页表记录索引位置,因为有1K个索引,所以用10位就可以表示了;

  • 通过索引可以找到对应的真正的页表地址,对应的有1K个页表记录,所以用10位就可以表示了;

  • 1个页有4K,通过12位就可以表示其页内偏移量了。

所以虚拟地址被分为了三部分:

1、10位表示索引偏移;

2、10位表示页表记录偏移;

3、12位表示页内偏移;

虽然这种方式增加了索引项,进一步增加了内存,但是减少了连续内存的使用,通过离散的内存就可以存储页表。这是对于32位系统,而64位系统采用了5级页表。

映射流程图

用户态申请内存时,只会申请对应的虚拟地址,不会直接为其分配物理内存,而是等到真正访问内存的时候,产生缺页中断,然后内核才会为其分配,然后为其建立映射,也就是建立对应的页表项。

TLB

TLB 就是一个缓存,放在CPU中。用来将虚拟地址和对应的物理地址进行缓存。当查询对应的物理地址的时候,首先查询TLB,如果TLB中存在对应的记录,就直接返回。如果不存在,就再去查询页表。

虚拟内存

虚拟内存指的是将硬盘中划出一段swap分区当作虚拟的内存,用来存放内存中暂时用不到的内存页,等到需要的时候再从swap分区中将对应的内存页调入到内存中。硬盘此时相当于一个虚拟的内存。

从逻辑上能够运行更大内存的程序,因为程序运行的时候并不需要把所有数据都加载到内存中,只需要将当前运行必要的相关程序和数据加载到内存中就可以了,当需要其他数据和程序的时候,再将其调入。

相较于真正的内存加载,虚拟内存需要将数据在内存和磁盘中不断切换,这是一个耗时的操作,所以速度比不上真正的内存加载。

总结

虚拟空间和物理内存都分为内核空间和用户空间。虚拟地址需要通过页表转化为物理地址,然后才能访问。

用户虚拟空间只能映射物理内存中的用户内存,无法映射到物理内存中的内核内存,也就是说,用户进程只能操作用户内存。

内核空间只能被内核申请使用,用户进程只能操作用户空间的物理内存和虚拟空间。当用户进程调用系统调用的时候,会将其对应的代码和数据运行在内核空间中。

所以当调用内核空间读取文件或者网络数据的时候,首先会将数据拷贝到内存空间,然后在将数据从内核空间拷贝到用户空间。因为用户进程不能访问内核空间。

关于传知摩尔狮

传知摩尔狮是广州传知信息科技有限公司旗下针对阿里云认证及云网创立的数字人才培训品牌,传知摩尔狮成立于2019年,致力于传播领先的教育理论,倡导更有效、更高效的学习范式,在IT职业教育领域,研究相关学科的教材教法和教学资源的整合,通过自主研发的学习服务平台推动IT人才的学习和发展,致力为中国云计算行业培养数字化人才。

摩尔狮在秉持传播知识、成就未来的理念下,2021年8月与阿里云达成深度合作,成为阿里云认证的战略级培训伙伴。并且,摩尔狮已和超过200家的互联网厂家签署了就业合作协议,为企业与国家持续培养输送面向未来的应用型人才。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1216809.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【小黑送书—第七期】>>程序员To架构师?一起来看架构师系列书籍推荐

相信大家都对未来的职业发展有着憧憬和规划,要做架构师、要做技术总监、要做CTO。对于如何实现自己的职业规划也都信心满满,努力工作、好好学习、不断提升自己。 相信成为一名优秀的架构师是很多程序员的目标,架构师的工作包罗万象&#xff…

工业智能网关:工业物联网智慧连接

工业智能网关是工业互联网的核心设备之一,它承担着连接设备、搜集数据、分析数据、设备控制和实现设备智能化管理的重要任务。随着工业互联网的快速发展,工业智能网关的作用变得越来越重要。 计讯物联5G/4G工业智能网关是一种连接工厂设备与互联网的关键…

如何优化谷歌商店里应用的评分评论1

低的评分和评论会引起的连锁反应,会对搜索和浏览可见性产生负面影响,同时拖累我们围绕应用商店优化所做的一切。所以解决负面评论的问题并提高应用的评分,对于提高应用商店的知名度至关重要。 1、分析应用评论。 我们需要分析应用程序当前获…

java学习part03基本类型

22-变量与运算符-标识符的使用_哔哩哔哩_bilibili 1.标识符(变量)命名规则 2.变量类型 3.整型 4.浮点型 5.char字符 6.布尔boolean 7.基本类型的自动提升 8.强制转换 9.String String只能连接 会把其他类型的表面量转成字符串比如"true" &…

深度学习入门(第三天)——卷积神经网络

卷积神经网络应用领域 CV领域发展: 比赛中预测错误率的百分比,每年逐步下降。Human是人类肉眼的识别能力,2016年开始已经远高于人类肉眼死别能力,后面就取消了该方向的比赛了。 检测任务: 分类与检索: 分类…

【实习】modbus

介绍 详解Modbus通信协议—清晰易懂 Modbus协议是一个master/slave架构的协议。有一个节点是master节点,其他使用Modbus协议参与通信的节点是slave节点。每一个slave设备都有一个唯一的地址。在串行和MB网络中,只有被指定为主节点的节点可以启动一个命令…

Nginx配置免费HTTPS详细教程

文章目录 背景说明环境准备说明安装Nginx及依赖环境配置HTTPS步骤步骤1:创建服务器私钥步骤2:创建签名请求的证书(CSR)步骤3:加载SSL支持的Nginx并使用私钥时去除口令步骤4:将密钥文件移动到Nginx配置文件目…

redis未授权访问漏洞利用

当redis服务(6379)端口对外开放且未作密码认证时,任意用户可未授权访问redis服务并操作获取其数据。 攻击机:10.1.1.100 kali 目标靶机:10.1.1.200 一、探测redis的未授权访问 首先在攻击机上使用nmap对目标机进行扫描,探测开放的…

强引用、软引用、弱引用、虚引用的区别

Java中的引用有四种,分为强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)4种,这4种引用强度依次逐…

单片机FLASH下载算法的制作

环境 硬件使用正点原子STM32F407探索者V2开发板 编程环境使用MDK 下载工具使用JLINK FLASH芯片使用W25Q128 什么是下载算法 单片机FLASH的下载算法是一个FLM文件,FLM通过编译链接得到,其内部包含一系列对FLASH的操作,包括初始化、擦除、写…

Python如何使用Networkx实现复杂的人物关系图?

Python如何使用Networkx实现复杂的人物关系图? 1 简单引入2 关于Networkx2.1 Networkx简单说明2.2 Networkx部分源码2.3 Networkx一个示例 3 人物关系图绘制过程3.1 创建原始数据3.2 获取目标文件数据3.3 获取颜色数据3.5 添加边数据3.6 定义边及权重3.7 图的布局、…

MySQL内部组件与日志详解

MySQL的内部组件结构 MySQL 可以分为 Server 层和存储引擎层两部分。 Server 层主要包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等)&am…

GoLong的学习之路,进阶,标准库之并发(context)补充并发三部曲,你真的明白context吗?

其实对于,context来说,如果只是用来做并发处理就有些不太合适。因为对于golang来说,context应用场景不仅在并发有用,并且在网络链接,http处理,gorm中都有体现。但是其实,本质来说。以上这些场景…

租赁小程序|租赁系统一种新型的商业模式

租赁市场是一个庞大的市场,它由出租人和承租人组成,以及相关的中介机构和供应商等。随着经济的发展和人们对灵活性的需求增加,租赁市场也在不断发展和壮大。特别是在共享经济时代,租赁市场得到了进一步的推动和发展。租赁系统是一…

Kontakt Factory Library 2(Kontakt原厂音色库2)

Kontakt Factory Library 2是一款由Native Instruments开发的音乐采样库。它是Kontakt采样器软件的官方库之一,提供了丰富的音色和音乐资源,可用于制作各种类型的音乐。 Kontakt Factory Library 2包含了数千个高质量的乐器采样,涵盖了各种乐…

Java实现俄罗斯方块游戏

俄罗斯方块游戏本身的逻辑: 俄罗斯方块游戏的逻辑是比较简单的。它就类似于堆砌房子一样,各种各样的方地形状是不同的。但是,俄罗斯方块游戏的界面被等均的分为若干行和若干列,因此方块的本质就是占用了多少个单元。 首先来考虑…

MySQL怎样处理排序⭐️如何优化需要排序的查询?

前言 在MySQL的查询中常常会用到 order by 和 group by 这两个关键字 它们的相同点是都会对字段进行排序,那查询语句中的排序是如何实现的呢? 当使用的查询语句需要进行排序时有两种处理情况: 当前记录本来就是有序的,不需要进…

京联易捷科技与劳埃德私募基金管理有限公司达成合作协议签署

京联易捷科技与劳埃德私募基金管理有限公司今日宣布正式签署合作协议,双方在数字化进程、资产管理与投资以及中英金融合作方面将展开全面合作。 劳埃德(中国)私募基金管理有限公司是英国劳埃德私募基金管理有限公司的全资子公司,拥有丰富的跨境投资经验和卓越的募资能力。该集…

pyhton将socket接收数据的字节改变并做处理

问题说明: 遇到发送过来的数据有一位是有问题的,但后面的数据是有效,还得用。甲方不愿意改信号。所以用代码直接在接收到数据后,将错误的数据位改正。 下面是修改后的demo例子: import socket def main(funcode):dict…

2013年12月1日 Go生态洞察:Go 1.2版本发布

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…