内容简介:理解Linux内存管理能够更好地理解进程的虚拟空间排布(当一个进程需要某块内存时,它会把自己的一个内存地址交由OS处理)。虽然进程只关心如何使用自己的线性排列的虚拟地址,而不需要关心物理内存的实际容量,以及如何使用真实的物理内存,但内存管理是内核最复杂的同时也是最重要的一部分;它是协作处理器与内核的关键流程,所以本文我们主要介绍Linux内存管理的相关知识点。典型的进程内存排布如下:
理解 Linux 内存管理能够更好地理解进程的虚拟空间排布(当一个进程需要某块内存时,它会把自己的一个内存地址交由OS处理)。
虽然进程只关心如何使用自己的线性排列的虚拟地址,而不需要关心物理内存的实际容量,以及如何使用真实的物理内存,但内存管理是内核最复杂的同时也是最重要的一部分;它是协作处理器与内核的关键流程,所以本文我们主要介绍Linux内存管理的相关知识点。
典型的进程内存排布如下:
操作系统有保护措施,阻止堆和栈的越界行为发生
内存管理
Linux把物理内存划分三个层次来管理
1、存储节点(node)
2、管理区(zone)
3、页(page)
内存管理涉及的领域: * 内存中物理内存页(内存管理的基本单位)的管理 * 分配大块内存的伙伴系统 * 分配小块内存的slab分配器 * 分配非连续内存块的vmalloc机制 * 进程的地址空间
NUMA计算机
NUMA(非一致性内存访问):多处理器计算机系统的各个CPU都有自己的本地内存;NUMA是稀疏且不连续的内存模型,在给定不同内存单元的访问时间可能不一样,系统的物理内存被划分为几个节点(node),在一个单独的节点内,任一给定CPU访问页面所需的时间都是相同的。
分页管理
分页是为了实现非连续分配,以便解决内存碎片问题;由于程序存在局部化特征,这意味着在特定时间内只有部分内存会被频繁访问,具体点说,进程空间中的text段(代码段)、堆、栈、共享库都是进程空间的某个特定部分,这样会导致进程空间是非常稀疏的,于是从硬件层面开始,页表实现采用分级 页表
。
在说明 页表
前,我们先介绍几个重要概念:页、页框、页帧
-
页:本质上是数据块,是信息的物理单位(段才是逻辑单位),是为了更高效和更经济的管理内存、线性地址被分为固定长度单位的组。
-
页框:本质上是存储区域,是内存存储单元,也是主存的一部分(可用于任何事情:存放内核数据、缓存数据、用户数据等);分页单元把所有的RAM分为固定长度的页框,每个页框包含一个页。
-
页帧:代表系统内存的最小单位,对内存中的每个页都会创建页描述符
struct page
的一个实例。页描述符存放在mem_map中,是内核中能区分哪些页框包含哪些进程,而哪些页框包含的是内核代码或内核数据。
层次化的 页表
是个映射表的概念,即从进程的线性地址映射到存储器的物理地址;主要用于支持大地址空间的快速、高效管理
页表也用于用户进程的虚拟地址空间和系统物理内存(内存、页帧)之间的关联,向每一个进程提供了一致肚饿虚拟地址空间,还可以在不不额外增加物理内存的情况下,将页换出到块设备来增加有效的可用内存空间。
Linux内核通过四级页表把虚拟内存空间分成5部分(4个页用于选择页,1个索引用于页内偏移)
内存区管理
Linux因为必须处理80X86体系结构,所以在硬件上限制了页框的使用方式,这中限制主要是由于硬件存在缺陷而引起的内存寻址问题。为了应对这种限制,Linux 2.6把内存节点分为几个区:
-
ZONE_DMA:低于16MB的页框
-
ZONE_NORMAL:高于16MB低于896MB的页框;大多数内核的操作只操作这个区域,系统内存由很多固定大小的内存块组成,这样的内存块叫“页”
-
ZONE_HIGHMEM:高端内存;高于896MB的框,在32位系统中,896MB边界上的页框不映射在内核线性地址空间的第四个GB,因此内核不能直接访问它们,不过64位系统不存在这个问题
当内核调用一个内存分配函数时,必须指明请求页所在的管理区
内核可以采用三种不同的机制将页框映射到高端内存(ZONE_HIGHMEM)中:
-
永久内核映射(可能阻塞进程)
-
临时内核映射(不阻塞进程)
-
非连续内存分配
非连续内存管理
把内存映射到一组连续的页框是最好的选择,这样会利用高速缓存并获得较低的平均访问时间。不过对于内存区的请求不是很频繁,那么通过连续的线性地址访问非连续的页框这样的一种分配方式会很有意义。
优点:避免外碎片
缺点:打乱内核页表
非连续内存管理的主要用途有三点:
-
为活动的交换区分配数据结构
-
为模块分配空间
-
给某些I/O驱动程序分配缓冲区
初始化
在启动过程期间,尽管内存管理尚未初始化(初始化后,交由伙伴系统承担),但内核仍然需要分配内存以创建各种数据结构,这个过程通过bootmem进行分配
bootmem作用于伙伴系统前,是在启动阶段的早期分配内存的,在需要分配内存时,它会逐位扫描位图(每次分配都必须从头扫到尾),然后每次通过对内存进行线性搜索实现分配,直至找到一个能提供足够连续页的位置,这个过程也叫 first-best。
伙伴系统
伙伴系统算法(fit-best)是内核为分配一组连续的 页框
而建立的一种分配策略,这个算法可以避免外碎片
伙伴系统的原理主要是通过一种技术纪录现存的空闲连续页的情况,以尽量为满足对小块的请求而非分隔打的空闲块
外碎片:指系统中无法利用的小存储块。 内碎片:指分配给作业的存储空间中未利用的部分
伙伴系统分配方案是一个结合2的方幂个分配器和空闲缓冲区合并计算的内存分配方案,它的基本思想是:把内存划分为很多不同页面规格的大块,当向内存申请特定大小的块时,会判断是否存在该大小的块,有则分配,无则把更大的块分为两部分,一部分进行分配,一部分处于空闲,用于以后的分配。当一个块被最终释放时,其伙伴将被检测出来,如果伙伴也处于空闲则被合并两者
slab
伙伴系统采用页框作为基本内存区,这适合对大块内存的请求,那么小块内存呢?这里我们使用slab分配器。
slab说白了就是一种空间换时间的技术,它把对象 分组
放到 高速缓存
中。包含高速缓存的内存区被划分为多个slab,每个slab由一个或多个连续页框组成,这些页框既包含分配对象,页包含空闲对象。
slab分配器所管理的对象可以在内存中对齐,通常是2的倍数,这个倍数称为 对齐因子
。对齐因子允许最大的范围是4096,4k页就是页框的大小。
内核使用 map_vm_area将分散的物理内存页连续映射到虚拟的vmalloc区域
提供小块内存不是slab分配的唯一任务,它也作为一个缓存,这个缓存主要针对经常分配与释放的对象。
使用slab有两大好处:
一、调用伙伴系统的操作对操作系统的数据和指令的高速缓存有相当的影响。更轻量的slab在可能的情况下减少了对伙伴系统的调用。
二、如果数据存储在伙伴系统直接提供的页中,那么其地址总是出现在2的幂次整数倍附近。这对CPU高速缓存有负面的影响,由于这种地址分布,使得某些缓存行过度使用,而某些则几乎为空。通过slab着色,slab分配器能均匀地分布对象,以实现均匀的缓存利用。
以上所述就是小编给大家介绍的《Linux内核学习:内存管理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Linux内核最新的连续内存分配器(CMA)——避免预留大块内存
- Linux内核内存管理算法Buddy和Slab
- Linux内核如何管理内存换入换出,如何实现磁盘缓存?
- Linux内核空间内存申请函数kmalloc、kzalloc、vmalloc的区别
- Symantec终端防护内核内存信息泄漏漏洞分析(CVE-2018-18366)
- 解决 Linux 内核问题实用技巧:Crash 工具结合 /dev/mem 任意修改内存
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。