Linux 内存管理(十一)调试信息
原图
/proc/meminfo
在 Linux 系统中查看内存信息最准确的方法是查看/proc/meminfo 节点信息,他包含当前时刻系统的所有的物理页面信息:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354vooxle@liushuai:~/workspace/blog$ cat /proc/meminfoMemTotal: 32766544 kBMemFree: 18617392 kBMemAvailable: 31598252 kBBuffers: 829808 kBCached: 11869936 kBSwapCached: 0 kBActive: 7991876 kBInactive: 4838568 kBActive(anon): 125680 kBInactive(anon): ...
Linux 内存管理(十)KSM
原图
概述
KSM 指 Kernel SamePage Merging,即内核同页合并,用于合并内容相同的页面。KSM 的出现是为了优化虚拟化中产生的冗余页面。
KSM 允许合并同一个进程或不同进程之间内容相同的匿名页面,这对应用程序来说是不可见的。把这些相同的页面合并成一个只读的页面,从而释放出多余的物理页面,当应用程序需要改变页面内容时,会发生写时复制。
使能 KSM
KSM 只会处理通过 madvise 系统调用显式指定的用户进程地址空间,因此用户程序想使用这个功能就必须在分配地址空间时显式地调用 madvise(addr,length,MADV_MERGEA BLE)。如果用户想在 KSM 中取消某一个用户进程地址空间的合并功能,也需要显式地调用 madvise(addr,length,MADV_UNMERGEABLE)。
下面是测试 KSM 的 test.c 程序的代码片段,使用 mmap():来创建一个文件的私有映射,并且调用 memset() 写入这些私有映射的内容缓存页面中。
1234567891011121314151617181920212223242526 ...
Linux 内存管理(九)页面迁移和内存规整
原图
声明本文转载自知乎 Linux 内存管理:页面迁移 和 Linux 内存管理 (16) 内存规整 内存相关文章
页面迁移
概述
页面迁移 (migrate) 是内存管理中很多功能实现的基础,比方说内存规整、NUMA balance、内存热插拔、CMA、HugeTLB、内存气球等等,本文主要讲一下页面迁移的主要流程和应用。
页面迁移的 API
migrate_pages( ) 这是页面迁移在内核态的主要接口,内核中涉及到页面迁移的功能大都会调到它。当然,在用户空间也存在着内存迁移相关的系统调用,最终也会调到它。这里我们通过 migrate_pages( ) 的几个形参展开全文。
1234567891011121314151617/* * migrate_pages - migrate the pages specified in a list, to the free pages * supplied as the target for the page migration * * @from: The li ...
Linux 内存管理(八)页面回收
原图
Linux 操作系统会使用存储设备作为交换分区,内核将很少使用的内存换出到交换分区,以便释放出物理内存,这个机制称为页交换(swapping),这些处理机制统称为页面回收 (pagereclaim)。
LRU 链表
Linux 内核中采用的页交换算法主要是经典 LRU 链表算法和第二次机会(secondchance)法。
LRU 是 Least Recently Used 的缩写,意为最近最少使用。根据局部性原理,LRU 假定最近不使用的页面在较短的时间内也不会频繁使用,在内存不足时,这些页面将成为被换出的候选者。内核使用双向链表来定义 LRU 链表,并且根据页面的类型将 LRU 链表分为 LRU_ANON 和 LRU_FILE。每种类型根据页面的活跃性分为活跃 LRU 链表和不活跃 LRU 链表,所以内核中一共有如下 5 个 LRU 链表。
不活跃匿名页面链表 LRU_INACTIVE_ANON
活跃匿名页面链表 LRU_ACTIVE_ANON
不活跃文件映射页面链表 LRU_INACTIVE_FILE
活跃文件映射页面链表 LRU_ACTIVE_FILE
不可回收页面 ...
Linux 内存管理(七)进程地址空间
原图
进程地址空间
进程地址空间在内核中使用 vm_area_struct 数据结构来描述,简称 VMA,表示进程地址空间或进程线性区。由于这些地址空间属于各个用户进程,因此在用户进程的 mm_struct 数据结构中有相应的成员,用于对这些 VMA 进行管理。
内存区域
进程地址空间(process address space)是指进程可寻址的虚拟地址空间,进程可以通过内核的内存管理机制动态地添加和删除内存区域,这些内存区域在 Linux 内核采用 VMA 数据结构来抽象描述。
每个内存区域具有相关的权限,如可读、可写或者可执行权限。若一个进程访问了不在有效范围的内存区域,或者非法访问了内存区域,或者以不正确的方式访问了内存区域,那么处理器会报告缺页异常。在 Linux 内核的缺页异常处理中会处理这些情况,严重的会报告“SegmentFault’”并终止该进程。
内存区域主要包含内容如下:
代码段映射:可执行文件中包含只读并可执行的程序头,如代码段和 init 段等
数据段映射:可执行文件中包含可读/可写的程序头,如数据段和未初始化数据段等
用户进程栈:通常位于用户空间的最 ...
Linux 内存管理(六)伙伴系统和 slab 分配器
原图
声明本文转载自知乎 兰新宇 内存相关文章
内存池
空闲链表(free list)
将内存中所有的空闲内存块通过链表的形式组织起来,就形成了最基础的 free list。内存分配时,扫描 free list 的各个空闲内存块,从中找到一个大小满足要求的内存块,并将该内存块从 free list 中移除。内存释放时,释放的内存块被重新插入到 free list 中。
假设现在内存的使用情况是这样的:
灰色部分代表已经被分配的内存块,白色部分代表空闲的内存块,大小分别是 48 字节,16 字节和 96 字节。如果此时内存分配的申请是 12 个字节,那么将有以下三种策略可以选择:
First fit(最先适配),就是从 free list 头部开始扫描,直到遇到第一个满足大小的空闲内存块,这里第一个 48 字节的内存块就可以满足要求。这种方法的优点是相对快一些,尤其是满足要求的空闲内存块位于链表前部的时候,但是在控制碎片数量上不是最优的。
Best fit(最佳适配),就是遍历 free list 的所有空闲内存块,从中找到和所申请的内存大小最接近的空闲内存块,这 ...
Linux 内存管理(五)页面分配器
原图
分配物理页面是内存管理中最复杂的部分,它涉及页面回收、内存规整、直接回收内存等相当错综复杂的机制。本节关注在内存充足的情况下如何分配连续物理内存。
page 数据结构
Linux 内核内存管理的实现以 page 数据结构为核心,其他的内存管理设施都基于 page 数据结构,如 VMA 管理、缺页中断、RMAP、页面分配与回收等。page 数据结构定义在 include/linux/mm_types.h 头文件中。
_refcount
_refcount 和__mapcount 是 page 数据结构中非常重要的两个引用计数,且都是 atomic_t 类型的变量。
_refcount 表示内核中引用该页面的次数。
当_refcount 的值为 0 时,表示该页面为空闲页面或即将要被释放的页面
当_refcount 的值大于 0 时,表示该页面已经分配给内核正在使用,暂时不会被释放
_mapcount
_mapcount 表示这个页面被进程映射的个数,即已经映射了多少个用户 PTE。每个用户进程都拥有各自独立的虚拟空间(256TB)和一份独立的页表,所以可能出现多个用户 ...
Linux 内存管理(四)虚拟内存管理
页表寻址过程
这里就是 cpu 将一个虚拟地址转换为物理地址的过程,整个过程是比较繁琐耗时的,因此这个过程一般在一个专门的硬件中完成就是 MMU、MMU 中为了可以加快速度引入了 TLB cache 快速查找 pte。我们需要注意到一点就是到了 PTE 这一级需要提供的是物理地址的页起始地址,这个地址是以 page size 为单位的,对于 4k 的 page,那么 pte 的低 12bit 就是没有使用的,而这 12bit 就正好用来作为 page 的权限控制位,对于 ARM64(39bit va)其高位 [40-63] 也没有使用因此也可以用来做一些其他事情。这里来看看 arm-v8 对低 12bit 的定义:
《Architecture Reference Manual ARMv8, for ARMv8-A architecture profile》里的 D4.3.2 ARMv8 translation table level 3 descriptor formats 一节中有相关描述:
ARM-v8 支持 5 种 L3 页表格式,其中我们关心的是 Page 4K gra ...
Linux 内存管理(三)物理地址管理
原图
内存管理发展史
内存管理的“远古时代”
在分页机制出现之前,操作系统有很多不同的内存管理机制,如动态分区法。如图(a)所示。剩余的 4MB 内存不足以装载进程 D,如图(b)所示,因为进程 D 需要 5MB 内存,这个内存末尾就成了第一个空洞(内存碎片)。假设某个时刻,操作系统需要运行进程 D,因为系统中没有足够的内存,所以需要选择一个进程来换出,为进程 D 腾出足够的空间。假设操作系统选择进程 B 来换出,这样进程 D 就装载到了原来进程 B 的地址空间里,于是产生了第二个空洞,如图(c)所示。假设操作系统某个时刻需要运行进程 B,也需要选择一个进程来换出,假设进程 A 被换出,那么操作系统中又产生了第三个空洞,如图(d)所示。
这种动态分区法在开始时是很好的,但是随着时间的推移会出现很多内存空洞,内存的利用率随之下降,这些内存空洞便是我们常说的内存碎片,动态分区法依然存在以下问题。
进程地址空间保护问题。所有的进程都可以访问全部的物理内存,所以恶意的程序可以修改其他程序的内存数据,这使进程一直处于危险的状态下。
内存使用效率低。如果即将运行的进程所需要的内存空间不 ...
Linux 内存管理(二)ARM64 的虚拟地址转换在 linux 中的实现
原图
arm64 内存管理
如图所示,ARM 处理器内核的 MMU 包括 TLB 和页表遍历单元(Table Walk Unit)两个部件。TLB 是一个高速缓存。一个完整的页表翻译和查找的过程叫作页表查询,页表查询的过程由硬件自动完成,但是页表的维护需要软件来完成。
下图为进程地址空间和物理地址空间的映射关系,左边是进程地址空间视图,右边是物理地址空间视图。进程地址空间又分成内核空间(Kermel Space)和用户空间(User Space)。无论是内核空间还是用户空间都可以通过处理器提供的页表机制映射到实际的物理地址。
页表
在 AArch64 架构中的 MMU 支持单一阶段的页表转换,同样也支持虚拟化扩展中两阶段的页表转换。
单一阶段的页表转换,把虑虚拟地址(VA)翻译成物理地址(PA)。
两阶段的页表转换:包括两个阶段。在阶段 1,把虚拟地址翻译成中间物 (Intermediate Phvsical Address,IPA);在阶段 2,把 IPA 翻译成最终 PA 另外,ARMv8 架构支持多种页表格式。具体如下。
ARMv8 架构的长描述符页表格式(Lon ...
