Linux 内存管理 | 虚拟内存管理:虚拟内存空间、虚拟内存分配
文章目录
- 虚拟内存空间
- 用户空间
- 内核空间
- 用户空间内存分配
- malloc
- 内核空间内存分配
- kmalloc
- vmalloc
Linux 内存管理 | 物理内存管理:内存碎片、伙伴系统、slab分配器
在上一篇博客中我介绍了Linux中对于物理内存的管理方式,这次再来介绍一下Linux对虚拟内存的管理方式
虚拟内存空间
即使是在现代,内存依旧是一项宝贵的资源,并且内存的管理以及访问控制向来都是难题。如果直接使用物理内存,通常都会面临以下几种问题
- 内存缺乏访问控制,安全性不足
- 各进程同时访问物理内存,可能会互相产生影响,没有独立性
- 物理内存极小,而并发执行进程所需又大,容易导致内存不足
- 进程所需空间不一,容易导致内存碎片化问题。
基于以上几种原因,Linux通过mm_struct
结构体来描述了一个虚拟的,连续的,独立的地址空间,也就是我们所说的虚拟地址空间。
在建立了虚拟地址空间后,并没有分配实际的物理内存,而当进程需要实际访问内存资源的时候就会由内核的请求分页机制产生缺页中断,这时才会建立虚拟地址和物理地址的映射,调入物理内存页。通过这种方法,就能够保证我们的物理内存只在实际使用时才进行分配,避免了内存浪费的问题。
下图则为Linux下的虚拟地址空间
在Linux中,虚拟内存空间的内部又被划分为用户空间与内核空间
用户空间
用户空间即进程在用户态下能够访问的虚拟地址空间,每个进程都有自己独立的用户空间,在32位系统下总容量为3G
用户空间由以下部分组成
- 栈:栈用来存放程序中临时创建的局部变量,如函数的参数、内部变量等。每当一个函数被调用时,就会将参数压入进程调用栈中,调用结束后返回值也会被放回栈中。同时,每调用一次函数就会创建一个新的栈,所以在递归较深时容易导致栈溢出。栈内存的申请和释放由编译器自动完成,并且栈容量由系统预先定义。栈从高地址向低地址增长
- 文件映射段:也叫共享区,文件映射段中主要包括共享内存、动态链接库等共享资源,从低地址向高地址增长。
- 堆:堆用来存放动态分配的内存。堆内存由用户申请分配和释放,从低地址向高地址增长。
- BSS段:BSS段用来存放程序中未初始化的全局变量和静态变量。
- 数据段:数据段用来存放程序中已初始化全局变量与静态变量。
- 代码段:代码段用来存放程序执行代码,也可能包含一些只读的常量。这块区域的大小在程序运行时就已经确定,并且为了防止代码和常量遭到修改,代码段被设置为只读。
内核空间
内核空间即进程陷入内核态后才能够访问的空间。虽然每个进程都具有自己独立的虚拟地址空间,但是这些虚拟地址空间中的内核空间 ,其实都关联的是同一块物理内存,如下图。
通过这种方法,保证了进程在切换至内核态后能够快速的访问内核空间。
在32位系统中,内核空间的大小为1G,从0xC0000000到0xFFFFFFFF
。
如上图,内核空间主要分为直接映射区和高端内存映射区两部分
直接映射区
从内核空间起始位置开始,从低地址往高地址增长,最大为896M
的区域即为直接映射区。
直接映射区的896M
的虚拟地址与物理地址的前896M
进行直接映射,所以虚拟地址和分配的物理地址都是连续的。
那么它们是如何转换的呢?其实它们之间存在着一个偏移量PAGE_OFFSET
,偏移量的大小即为0xC0000000
。
所以虚拟地址 = PAGE_OFFSET + 物理地址
高端内存映射区
在上面也提到了,内核空间利用直接映射区来将896M
的内存直接映射到物理内存中,但是我们的物理内存远远不止这么点,那么对于剩下的物理内存的寻址工作,就交给了高端内存映射区
由于我们的内核空间只有1G
,而直接映射区又占据了896M
,因此我们将剩下的128M
空间划分成了三个高端内存的映射区,从上往下分别是固定内存映射区,永久内存映射区,动态内存映射区
- 动态内存映射区:该区域的特点是虚拟地址连续,但是其对应的物理地址并不一定连续。该区域使用内核函数
vmalloc
进行分配,分配的虚拟地址的物理页可能会处于低端内存,也可能处于高端内存 - 永久内存映射区:该区域可以访问高端内存。使用
alloc_page(_GFP_HIGHMEM)
分配高端内存页,或者使用kmap
将分配的高端内存映射到该区域 - 固定内存映射区:该区域的每个地址项都服务于特定的用途,如
ACPI_BASE
用户空间内存分配
malloc
了解C语言的同学都应该知道,在C语言中我们可以使用malloc
来在用户空间中动态的分配内存,而malloc
作为库函数,其本质就是对系统调用进行了一层封装,因此在不同的系统下其实现不同。
在Linux中,当我们申请的内存小于128K
时,malloc
会使用sbrk
或者brk
在堆区分配内存。而当我们申请大于128K的大块空间时,会使用mmap
在映射区进行分配。
但是由于上述的brk/sbrk/mmap
都属于系统调用,因此当我们每次调用它们时,就会从用户态切换至内核态,在内核态完成内存分配后再返回用户态。
倘若每次申请内存都要因为系统调用而产生大量的CPU开销,那么性能会大打折扣。并且从上面的图我们也可以看出来,堆是从低地址往高地址增长,如果低地址的内存没有被释放,则高地址的内存就不能被回收,就会产生内存碎片的问题。
malloc是如何实现解决这个问题的呢?
为了减少内存碎片和系统调用的开销,malloc
在底层采用了内存池来解决这个问题。
它会先申请大块内存作为堆区,然后将这块内存拆分为多个不同大小的内存块,以块作为内存管理的基本单位。同时,会使用隐式链表来连接所有的内存块,包括已分配块和未分配块。为了方便内存空闲块的管理,malloc采用显式链表来管理所有的空闲块。
当我们调用malloc进行内存分配时,就会去搜索空闲链表,找到满足需求的内存块,如果内存块过大,则会将内存块拆分为两部分,即一部分用来分配,另一部分则变为新的空闲块。
同理,当我们释放内存块时,会通过遍历隐式链表,判断释放块前后内存块是否空闲,来决定是否需要合并内存块
内核空间内存分配
在内核空间中,通过与malloc
类似的两个系统调用来进行内存的分配,它们 分别是kmalloc
和vmalloc
kmalloc
kmalloc
与上面介绍的用户空间的malloc
函数非常类似,其用于为内核空间的直接内存映射区分配内存。
kmalloc
以字节为分配单位,通常用于分配小块内存,并且kmalloc
确保分配的页在物理地址上是连续的(虚拟地址也必然连续)。并且kmalloc
为了防止内存碎片的问题,其底层页面分配算法是基于slab分配器实现的。
vmalloc
vmalloc用于为内核空间中的动态内存映射区进行内存分配。
vmalloc
的工作方式与kmalloc
类似,不同的地方在于vmalloc
分配的内存只保证了虚拟地址是连续的,而物理地址不一定连续。它通过分配非连续的物理内存块,再通过修正页表的映射关系,把内存映射到虚拟地址空间的连续区域,就能够做到这一点。
如上图,就是内核空间中进行内存分配的具体流程
Linux 内存管理 | 虚拟内存管理:虚拟内存空间、虚拟内存分配相关推荐
- linux 内存与磁盘管理
内存和磁盘使用率查看 内存使用状况查看 free && top 如果没有使用swap(虚拟内存),在linux内存被即将占满的情况下 ,内核会随机杀死占用较大的应用/进程. ## 以兆 ...
- 六、操作系统——内存管理的概念(空间的分配与回收、空间的扩充、地址转换、存储保护)
一.概述 二.操作系统作为系统资源的管理者,当然也需要对内存进行管理,要管些什么呢? 1. 内存空间的分配与回收 连续分配:指为用户进程分配的必须是一个连续的内存空间. 1. 单一连续分配 在单一连续 ...
- Linux内存、CPU及磁盘空间测试工具
一.内存测试工具 1.目的 测试当服务器内存空间使用率超过一定范围时,系统是否触发告警. 2.测试方法 1.Ubuntu服务器编译c代码 若服务器无编译c代码的gcc命令,需先安装gcc(若已安装可跳 ...
- 万字长文,别再说你不懂Linux内存管理了(合辑),30 张图给你安排的明明白白...
之前写了两篇详细分析 Linux 内存管理的文章,读者好评如潮.但由于是分开两篇来写,而这两篇内容其实是有很强关联的,有读者反馈没有看到另一篇读起来不够不连贯,为方便阅读这次特意把两篇整合在一起,看这 ...
- linux c 将虚拟地址转化为物理地址_面试不懂 Linux 内存管理?我用 20 张图给你讲明白...
微信搜索公众号「 后端技术学堂 」回复「1024」获取50本计算机电子书,回复「学习路线」获取超详细后端技术学习路线思维导图,文章每周持续更新,我们下期见! 大家好,我是柠檬哥. 分享编程学习,助力程 ...
- Linux内存管理之基本概念介绍(一)
Linux内存管理之基本概念介绍(一) Linux内存管理之物理内存管理(二) Linux内存管理之内存管理单元(MMU)(三) Linux内存管理之分配掩码(四) Linux内存管理之伙伴系统(五) ...
- Linux内存管理图解
前提约定:本文讨论技术内容前提,操作系统环境都是 x86架构的 32 位 Linux系统. 虚拟地址 即使是现代操作系统中,内存依然是计算机中很宝贵的资源,看看你电脑几个T固态硬盘,再看看内存大小就知 ...
- 探索 Linux 内存模型--转
引用:http://www.ibm.com/developerworks/cn/linux/l-memmod/index.html 理解 Linux 使用的内存模型是从更大程度上掌握 Linux 设计 ...
- 操作系统——实验叁——主存空间的分配与回收
一. 实验目的 采用可变式分区管理,使用最佳适应算法实现主存的分配与回收 通过本次实验,帮助学生理解在可变式分区管理方式下,如何实现主存空间的分配与回收. 二. 实验内容 主存是中央处理机能直接存取指 ...
- linux内存管理的主要概念是虚拟内存,你知道linux内存管理基础及方法?
描述 一.基本概念 (1)物理内存和虚拟内存 物理内存:系统硬件提供的真实物理内存 虚拟内存:利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为swap,swap类似于windows的虚拟 ...
最新文章
- JFreeChart_API
- vue方法传值到data_vue组件传值的几种方式
- 机器学习和图像识别是怎样彻底改变搜索的?
- 同一个联盟,同一个梦想 —— 微软 .NET 俱乐部 2006 年在线发布会
- VTK:几何对象之Planes
- MySql恢复密码的过程
- 【Boost】boost库中thread多线程详解2——mutex与lock
- select函数及fd_set介绍
- Java中的迭代器设计模式–示例教程
- Python中正则匹配使用findall时的注意事项
- 144显示器只有60_3199元34寸144Hz高刷新曲面带鱼屏显示器咋样?用过才知道
- java agentlib 作用_javaagent 简介
- LESS CSS 框架简介
- C#毕业设计——基于C#+asp.net+ACCESS的电子商务网站设计与实现(毕业论文+程序源码)——电子商务网站
- 互联网公司对Android,iOS开发工程师的职位要求
- 2021高考成绩查询怎么查小分,2021微信哪个小程序可以查成绩 高考成绩怎么查
- 商业与计算机科学,新加坡留学:楷博高等教育商业信息系统与计算机科学课程解析...
- python 学习爬取哔哩哔哩今日热门的前100个视频
- 系统突然变慢的处理方案
- 人工智能技术与物联网的融合