32查运行内存的map文件_linux内存管理

概念先行

先理解内存管理中的几个概念:内存,主存,缓存,外存,虚拟内存,物理内存,虚拟地址,物理地址

外存:

计算机的外部存储,比如硬盘(机械硬盘、固态硬盘、混合硬盘),usb

内存:

用于计算机运行过程中的临时存储,断电清除(这也是我们计算机休眠能保留进程状态,而断电关机不行的原因)。内存现在特指动态随机存储器(DRAM),就是我们电脑的内存条,也就是我们说的物理内存,等价于主存。也就是内存~物理内存~主存~内存条

缓存:

在内存管理子系统中指的是静态随机存储器(SRAM),比如cpu与主存之间的多级缓存(L1, L2 和 L3 高速缓存),当然计算机广义上的缓存远不止这些

虚拟内存:

抽象概念,虚拟内存的引入旨在为每个进程提供统一线性一致的地址空间,真正的地址则有MMU(内存管理单元)控制映射至对应的物理内存空间,而虚拟地址,物理地址则代表对应空间的偏移地址

需要注意的是,对于某一特定指令架构的计算机(比如32位),虚拟内存能够映射的地址,一部分映射至物理内存,当物理内存已满时,则进行页面置换映射至对应的磁盘空间。也就是虚拟内存地址包括(物理内存与部分磁盘空间)的地址映射

为什么呢?比如32位系统,内存条只有256M,此时32位系统最多只能用4G内存(虚拟内存):32位系统,即内存地址长度为32,最多映射2^32=2^2*2^30=4G个字节。远远大于内存条,则在进程运行过程中,当运行数据超过内存限度,部分数据自动“溢出”,这时系统会将磁盘上的部分空间模拟成虚拟内存,并将原来映射到物理内存中的暂时不运行的程序或不使用的数据置换到磁盘中,腾出更多物理内存空间并重新映射至虚拟内存中被调用

1008cfac50673c4f01f1cca65c2621ed.png

了解了概念,简单看下内存管理子系统虚拟地址(virtual adress)与物理地址(physical address)的关系

进程访问某个虚拟地址(虚拟页号+偏移量),cpu通过内存管理单元(MMU)找到对应到物理内存中的物理地址并返回,过程如下:

  • 查询快表缓存(TLB)找到是否有缓存的页帧(物理页号),有则直接返回缓存的内容

  • 否则在页表(分页管理)中,找到虚拟地址的虚拟页号对应的物理页号的起始地址,返回物理地址(物理地址=物理起始地址+偏移量)

用户空间与内核空间

为了避免用户进程直接操作内核,保证内核安全,操作系统将虚拟内存划分为两部分,一部分是内核空间(Kernel-space),一部分是用户空间(User-space)。在 Linux 系统中,内核模块运行在内核空间,对应的进程处于内核态;而用户程序运行在用户空间,对应的进程处于用户态。

用户空间的进程无法直接访问内核函数,比如由调度系统切换至内核态,才能调用内核函数。这也就是为啥我们说调用glibc库的fread函数的时候需要会发生上下文切换,并且发生两次拷贝(磁盘 -> 内核缓冲区(read buffer) -> 用户缓冲区)的原因

虚拟内存分为用户空间与内核空间,通常按3:1分配,比如32位系统的能表示的最大虚拟地址为4G,将最高的 1G 的字节(从虚拟地址 0xC0000000 到 0xFFFFFFFF)供内核进程使用,称为内核空间;而较低的 3G 的字节(从虚拟地址 0x00000000 到 0xBFFFFFFF),供各个用户进程使用,称为用户空间。下图是一个进程的用户空间和内核空间的内存布局:

b0af10a7a0cad6f1a43de2fd9c805240.png

内核空间

内核空间总是驻留在内存中,它是为操作系统的内核保留的。应用程序是不允许直接在该区域进行读写或直接调用内核代码定义的函数的。上图左侧区域为内核进程对应的虚拟内存,按访问权限可以分为进程私有和进程共享两块区域。

  • 进程私有的虚拟内存:每个进程都有单独的内核栈、页表、task 结构以及 mem_map 结构等。

  • 进程共享的虚拟内存:属于所有进程共享的内存区域,包括物理存储器、内核数据和内核代码区域。

用户空间

每个用户进程都有一个单独的用户空间,用户空间包括以下几个内存区域:

  • 运行时栈:由编译器自动释放。存放函数的参数值,局部变量和方法返回值等。每当一个函数被调用时,该函数的返回类型和一些调用的信息被存储到栈顶,调用结束后调用信息会被弹出弹出并释放掉内存。栈区是从高地址位向低地址位增长的,是一块连续的内在区域,最大容量是由系统预先定义好的,申请的栈空间超过这个界限时会提示溢出,比如递归申请会出现“栈溢出”现象

  • 内存映射区域:例如将动态库,共享内存等虚拟空间的内存映射到物理空间的内存,一般是 shm,mmap 函数所分配的虚拟内存空间。

  • 运行时堆:用于存放进程运行中被动态分配的内存段,位于 BSS 和栈中间的地址位。由开发人员申请分配(malloc)和释放(free)。堆是从低地址位向高地址位增长,采用链式存储结构。频繁地 malloc/free 造成内存空间的不连续,产生大量碎片。当申请堆空间时,库函数按照一定的算法搜索可用的足够大的空间。因此堆的效率比栈要低的多。

  • 未初始化的数据段:存放未初始化的全局变量,BSS 的数据在程序开始执行之前被初始化为 0 或 NULL。

  • 已初始化的数据段:存放已初始化的全局变量,包括静态全局变量、静态局部变量以及常量。

  • 代码段:存放 CPU 可以执行的机器指令,该部分内存只能读不能写。通常代码区是共享的,即其它执行程序可调用它。假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段。

当我们写完代码,编译,链接并且生成可执行文件后,得到的这个东西就是一系列二进制代码的集合,我们管这东西叫做程序,存储在磁盘上。只有当我们执行这个文件后,程序才会被操作系统读入内存运行,比如

[mqq@9-37-26-84 ~]$ size /usr/local/bin/curltext    data     bss     dec     hex filename155348    1348     272  156968   26528 /usr/local/bin/curl

上面命令输出的地址就是各个分段的虚拟地址,当进程执行一个程序时,需要先从先内存中读取该进程的指令,然后执行,获取指令时用到的就是虚拟地址。这个虚拟地址是程序链接时确定的(内核加载并初始化进程时会调整动态库的地址范围)。为了获取到实际的数据,CPU 需要将虚拟地址转换成物理地址,CPU 转换地址时需要用到进程的页表(Page Table),而页表(Page Table)里面的数据由操作系统维护。

内存管理机制

分段管理(Segmentation)

90f5413502978a46161944f2c8e5edc7.png

分段机制下的虚拟地址由两部分组成,段选择子和段内偏移量。

  • 段选择子:保存在段寄存器里面。段选择子里面最重要的是段号,用作段表的索引。段表里面保存的是这个段的基地址、段的界限和特权等级等控制位。

  • 段内偏移量:位于 0 和段界限之间,如果段内偏移量是合法的,则段基地址+段内偏移量=物理内存地址。

程序若干个逻辑分段(栈,堆,数据等)会映射到对应的物理内存分段,如果要访问(栈)段 3 中偏移量 500 的虚拟地址,我们可以计算出物理地址为,段 3 在物理内存的基地址 7000 + 偏移量 500 = 7500。

分段的内存碎片问题(内存碎片的产生可自行google)比较严重,所以引入了分页管理(更小颗粒度)

分页管理

分页是把整个虚拟和物理内存空间切成一段段固定尺寸的页大小。在 Linux 下,1页=4KB。

8d0fe91616fa27468e99d65eb04ac850.png

在分页机制下的虚拟地址有两部分组成,分别是页号和页内偏移。

  • 页号:作为页表的索引,映射虚拟页号到物理页号在物理内存的基地址

  • 页内偏移量:上面的基地址+页内偏移=物理内存地址

下面举个例子,虚拟内存中的页通过页表映射为了物理内存中的页,如下图:

这里讲一下MMU中具体的页表映射逻辑

0e1cad21dc0e1b0d3262fca65cfa6ab2.png

虚拟页面中每一项包含多个控制位

  1. VALID 位表示是否缓存

  2. SUP 位表示进程是否必须运行在超级用也就是内核模式下才能访问该页

  3. WRITE 位控制页面的写访问

  4. EXRC 位控制页面的执行

在任意时刻,虚拟页面分为三个不同的状态:

  1. 未分配的,VM 系统还未分配(或者创建)的页,未分配的页没有任何数据和它们关联,因此不占用任何内存空间。

  2. 缓存的,当前已缓存在物理内存中的已分配页。

  3. 未缓存的,未缓存在物理内存中的已分配页。

思考个问题,如果进程访问某个虚拟页面,但没有对应的物理内存映射,会发生什么?

会触发页中断,就是我们说的Page Fault

648998fe6e4169e7742ccb2b407c2b28.png

上图所示,访问不到虚拟页的内存的时候

(2)检测Valid=0,发生缺页中断,然后交给缺页中断处理器处理逻辑

(3)缺页中断处理器,从物理内存中选择某一合适的页置换(swap)到磁盘,然后从磁盘中创建新的虚拟页面,更新虚拟页与物理页的映射,然后返回用户进程。当异常处理程序返回时,它会重启执行导致缺页的指令,该指令会将导致缺页的虚拟地址重新发送到MMU。此时该虚拟页号已经在主存(物理内存)中了,那么就是页命中了。

简单分页会有空间的问题,因为每个进程都维护自己的页表,空间浪费,所以引入了多级页表机制,从而大大减少页表空间

2fb25a9af49c0475d756d5f692c4f9d1.png

回到刚才的内存碎片的问题,内存碎片通常分为内部碎片和外部碎片:

  • 内部碎片是由于采用固定大小的内存分区,当一个进程不能完全使用分给它的固定内存区域时就产生了内部碎片,通常内部碎片难以完全避免。

  • 外部碎片是由于某些未分配的连续内存区域太小,以至于不能满足任意进程的内存分配请求,从而不能被进程利用的内存区域。

一般我们解决的是外部碎片问题,而现在操作系统普遍采用的段页式内存分配方式,就是将进程的内存区域分为不同的段,然后将每一段由多个固定大小的页组成。通过页表机制,使段内的页可以不必连续处于同一内存区域,从而减少了外部碎片,然而同一页内仍然可能存在少量的内部碎片,只是一页的内存空间本就较小,从而使可能存在的内部碎片也较少。

段页式内存管理

86aed436d6998f271dc1c7be55f5c69b.png

段页式内存管理机制下,虚拟地址由段号、段内页号和页内位移三部分组成。

段页式地址变换中要得到物理地址须经过三次内存访问:

  • 第一次访问段表,得到页表起始地址;

  • 第二次访问页表,得到物理页号;

  • 第三次将物理页号与页内位移组合,得到物理地址。

总的来说,避免外碎片的方法有两种:

  • 利用分页单元把一组非连续的空闲页框映射到连续的线性地址

  • 开发一种适当的技术来记录现存的空闲的连续页框块的情况,以尽量避免为满足对小块的请求而分割大的空闲快

第一种方案的意思是,我们使用地址转换技术,把非连续的物理地址转换成连续的线性地址。就是上面提到的段页式内存分配
第二种方案的意思是,开发一种特有的分配技术来记录下来空闲内存的情况,从而解决内存碎片问题。linux系统下采取了伙伴系统(buddy)和slab以及相关的分配算法,回收机制提高了内存的利用率(具体感兴趣的可以自行google)。

整体内存管理架构

e12fc9b5f740245e8f9613de77f029e5.png

总结:

内存分为虚拟内存和物理内存,虚拟内存分成用户空间和内核空间(3:1),内存管理有分段,分页,段页式机制,地址转换由MMU负责(TLB+页表)映射,涉及知识点有页面置换,缺页错误,内存碎片等

要对内存管理子系统有深入的了解,还需要了解虚拟内存管理子系统中的各种机制与算法

  1. buddy (伙伴系统(buddy system):以页为单位管理和分配内存)

  2. slab(基于伙伴系统分配的大内存进一步细分成小内存分配)

  3. zone(内核地址映射逻辑)

  4. kswapd(页面换入换出,页缓存回收,zone扫描)

  5. bdflush(延迟dirty buffers刷盘机制)

但是本篇文章旨在为了对内存管理有个整体的了解,更深入的会放到后面的文章中

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

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

相关文章

react usecontext_鬼才!我居然把 Vue3 的原理用到了 React 上?

前言vue-next是Vue3的源码仓库,Vue3采用lerna做package的划分,而响应式能力vue/reactivity被划分到了单独的一个package中。如果我们想把它集成到React中,可行吗?来试一试吧。使用示例话不多说,先看看怎么用的解解馋吧…

微信多开txt_在电脑上怎么实现微信多开的效果

现在越来越多的年轻人在电脑办公的时候,不止有一个微信号,由于工作、家庭等各方面因素,想自己能在一个电脑上打开多个微信怎么办?下面小编就把自己的所学分享给大家一.首先在电脑桌面上新建一个txt文本文件,把这个文档…

vue slot scope使用_20、slot插槽的用法

重点:单个插槽、具名插槽、作用域插槽的用法;访问插槽的方法。其实本小白对插槽理解的还不深,哪些场景会经常用到插槽也不了解。但是本着“大胆猜测”的理念,我的猜测如下:假设有 父组件A,有 子组件B、子组…

python工作目录_如何使用python 3获取当前工作目录?

When I run the following script in IDLE import os print(os.getcwd()) I get output as D:\testtool but when I run from cmd prompt, I get c:\Python33>python D:\testtool\current_dir.py c:\Python33 How do I get same result which I got using IDLE ? 解决方案 …

flutter刷新页面_用Flutter实现58App的首页

背景Flutter作为全新跨平台应用框架,在页面渲染和MD开发上优势明显,可谓是业界一枝独秀。正好最近有这样的一个机会学习Flutter开发,我们便尝试用它开发一个MD风格的较复杂页面,来比较跟原生应用开发的优势。也是想通过对新框架的…

python调用报表制作工具_使用Python轻松制作漂亮的表格

Python太有用而且很方便 图表可以用matplotlib轻松制作,数值计算只要有numpy就行。 最近,Python被广泛用于机器学习系统的研究,甚至还能制作游戏。 我突然想知道:“是否可以用Python来制作图表而不是表格?” 这个时候&…

小米网关控制空调伴侣_小爱同学怎么控制灯?

说说我们神奇小爱同学吧,小爱同学是小米旗下的一款智能AI音箱,会根据您的指令来操作电器设备,比如说开关灯,那么小爱同学怎么控制灯?如果家里的是传统的灯泡,不是智能灯连接还能控制吗?今天蜜罐…

bochs上网镜像怎么上网_【干货科普】上网慢!经常掉线!怎么办?

文章来源:鲜枣课堂(ID:xzclasscom)作为也算是懂点技术的半专业人士,我们放假回去,遇到亲友,很可能被问到这样的问题——“我的手机(电脑)上网经常掉线,是为什么?”“我的手机(电脑)上网总是很慢…

sql 中位数_【PL/SQL 自定义函数】 常用场景

看完这章后你会学习到以下内容:1.练习场景2.面试场景3.工作应用场景总览思维导图:面试部分:1.创建函数,从emp表中查询指定员工编号的职工的工资CREATE OR REPLACE FUNCTION CHECK_SAL(F_EMPNO IN EMP.EMPNO%TYPE) RETURN NUMBER ISV_SAL VARC…

以下python注释代码格式正确的是_Python文件头注释的含义,你肯定不懂

本文档描述了Python语言文件头里典型注释的含义。 1. 指定解释器 不管在linux还是在windows下,要运行一个python文件(比如hello.py)的方式一般都是 python ./hello.py 1 然而,有一种方式可以直接运行hello.py文件,那就…

python异步和进程_12.python进程\协程\异步IO

进程Python中的多线程无法利用多核优势 , 所以如果我们想要充分地使用多核CPU的资源 , 那么就只能靠多进程了multiprocessing模块中提供了Process , Queue , Pipe , Lock , RLock , Event , Condition等组件 , 与threading模块有很多相似之处1.创建进程from multiprocessing im…

swift date 计算差_[Swift 设计模式] 适配器

更多内容,欢迎关注公众号:Swift花园喜欢文章?不如来个 ➕三连?关注专栏,关注我 将一个不兼容的对象转换成目标接口或者类,这是适配器模式的作用。下面这件东西是适配器模式在现实世界中最贴切的表达。 USB-…

委外订单_听听晚报-英特尔扩大芯片委外订单、苹果秋季或举行两场发布会

英特尔扩大芯片委外订单据外媒报道称,美国半导体厂商英特尔已与中国台湾芯片制造厂商台积电达成协议,明年开始采用后者7nm的优化版本6nm制程量产处理器或显卡,预估投片量将达到18万片。该消息发出后,资本市场反应剧烈,…

ios系统可以使用python吗_4. 在苹果系统上使用 Python

4.1.获取和安装 MacPython Mac OS X 10.8 附带 Apple 预安装的 Python 2.7 。 如果你愿意,可以从 Python 网站( https://www.python.org )安装最新版本的 Python 3 。 Python 的当前“通用二进制”版本可以在 Mac 的新 Intel 和传统 PPC CPU …

打开另外一个页面_如何在PDF页面中插入图片?

如何给PDF添加图片?有些时候为了丰富PDF的文档内容,需要添加一些图片,相比Word或PPT文档可以直接插入图片,而PDF的操作很多人可能并不熟悉,下面一起来看看如何在PDF文档中插入图片。关于PDF文档插入图片分为两种情况&a…

spring boot mybatis 整合_MyBatis学习:MyBatis和Spring整合

1. 整合的工程结构首先我们来看下整合之后的工程结构是什么样的。2. 配置文件在于spring整合之前,mybatis都是自己管理数据源的,然后sqlSessionFactory是我们自己去注入的,现在整合了,这些都要交给spring来管理了,来看…

华三路由交换配置命令_华三路由器交换机配置命令

路由器:1、进入SETUP模式Router#setup2、时间设置router#clock set hh:mm:ss date moth year3、router>show historyRouter>terminal history size lines4、router#show version5、router#show running-config6、router#show starup-config7、router(config)#hostname na…

python中缩进_python编程中的缩进是什么意思

Python最具特色的是用缩进来标明成块的代码。我下面以if选择结构来举例。if后面跟随条件,如果条件成立,则执行归属于if的一个代码块。 下面对比C语言来看一下if ( i > 0 ) { x 1; y 2; } 如果i > 0的话,我们将进行括号中所包括的两个…

返回后的数据处理_【掘金使用技巧2】掘金返回数据中时间的处理方法

掘金输出的时间数据处理方法掘金在为使用者提供数据时,有一类数据处理起来有些麻烦,这类数据就是时间数据。它们长这样:或者这样:查看一下它们的类型,发现有datetime,datetime64,Timestamp等等。这么多各种各样的类型&…

springboot jwt token前后端分离_为什么要 前后端分离 ?

作 者:互扯程序来 源:互扯程序广而告之:由于此订阅号换了个皮肤,系统自动取消了读者的公众号置顶。导致用户接受文章不及时。您可以打开订阅号,选择置顶(星标)公众号,重磅干货,第一时间送达&…