Linux 并发与同步(一)自旋锁
原图
经典自旋锁
如果临界区中只有一个変量,那么原子变量可以解決问题,但是临界区有一个数据操作的集合,需要通过锁机制来保障,自旋锁( spinlock)是 Linux 内核中最常见的锁机制。
忙等待的锁机制。操作系统中锁的机制分为两类,一类是忙等待,另一类是睡眠等待
同一时刻只能有一个内核代码路径可以获得该锁
要求自旋锁持有者尽快完成临界区的执行任务,特别是自旋锁临界区里不能睡眠
自旋锁可以在中断上下文中使用
自旋锁的实现
先看 spinlock 数据结构的定义:
12345678910111213141516171819202122232425262728293031323334353637383940<include/linux/spinlock_types.h>typedef struct spinlock { union { struct raw_spinlock rlock;#ifdef CONFIG_DEBUG_LOCK_ALLOC# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map) ...
Linux 内存管理(十二)内存调优
原图
内存管理调优参数
对服务器或者嵌入式产品做性能调优的过程中,避免不了需要深入了解和使用 Linux 内内存管理模块提供的调优参数。Linux 内核支持的内存管理调优参数都在/proc/sys/vm 目录下面,共有 40 多个调优参数,如下所示:
123456789root@liushuai:/proc/sys/vm# lsadmin_reserve_kbytes dirty_ratio lowmem_reserve_ratio mmap_rnd_bits oom_kill_allocating_task stat_refreshblock_dump dirtytime_expire_seconds max_map_count mmap_rnd_compat_bits overcommit_kbytes swappinesscompact_memory dirty_writebac ...
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): 6 ...
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() 写入这些私有映射的内容缓存页面中。
123456789101112131415161718192021222324252627 ...
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 list ...
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 gran ...