分析linux内核中的slub内存管理算法
1. 分析的linux内核源码版本为4.18.0
2. 与slub相关的内核配置项为CONFIG_SLUB
3. 一切都从一个结构体数组kmalloc_caches开始,它的原型如下:
struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + ] __ro_after_init;
3.1 这个数组定义在mm/slab_common.c中
3.2 KMALLOC_SHIFT_HIGH是如何定义的呢?
#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)
#define PAGE_SHIFT 12 (各个架构下的定义都有些差异,如果是arm64,那么是通过CONFIG_ARM64_PAGE_SHIFT来指定的,这个配置项在arch/arm64/Kconfig文件中定义,默认为12,也就是默认页面大小为4KiB,笔者以arm64为例)
那么KMALLOC_SHIFT_HIGH=PAGE_SHIFT + 1 = 12 + 1 = 13,KMALLOC_SHIFT_HIGH+1=13+ 1= 14说明kmalloc_caches数组中有14个元素,每个元素是kmem_cache这个结构体
3.3 分析一下sturct kmem_cache这个结构体
/*
* Slab cache management.
*/
struct kmem_cache {
struct kmem_cache_cpu __percpu *cpu_slab;
/* Used for retriving partial slabs etc */
slab_flags_t flags;
unsigned long min_partial;
unsigned int size; /* The size of an object including meta data */
unsigned int object_size;/* The size of an object without meta data */
unsigned int offset; /* Free pointer offset. */
#ifdef CONFIG_SLUB_CPU_PARTIAL
/* Number of per cpu partial objects to keep around */
unsigned int cpu_partial;
#endif
struct kmem_cache_order_objects oo; /* Allocation and freeing of slabs */
struct kmem_cache_order_objects max;
struct kmem_cache_order_objects min;
gfp_t allocflags; /* gfp flags to use on each alloc */
int refcount; /* Refcount for slab cache destroy */
void (*ctor)(void *);
unsigned int inuse; /* Offset to metadata */
unsigned int align; /* Alignment */
unsigned int red_left_pad; /* Left redzone padding size */
const char *name; /* Name (only for display!) */
struct list_head list; /* List of slab caches */
#ifdef CONFIG_SYSFS
struct kobject kobj; /* For sysfs */
struct work_struct kobj_remove_work;
#endif
#ifdef CONFIG_MEMCG
struct memcg_cache_params memcg_params;
/* for propagation, maximum size of a stored attr */
unsigned int max_attr_size;
#ifdef CONFIG_SYSFS
struct kset *memcg_kset;
#endif
#endif #ifdef CONFIG_SLAB_FREELIST_HARDENED
unsigned long random;
#endif #ifdef CONFIG_NUMA
/*
* Defragmentation by allocating from a remote node.
*/
unsigned int remote_node_defrag_ratio;
#endif #ifdef CONFIG_SLAB_FREELIST_RANDOM
unsigned int *random_seq;
#endif #ifdef CONFIG_KASAN
struct kasan_cache kasan_info;
#endif unsigned int useroffset; /* Usercopy region offset */
unsigned int usersize; /* Usercopy region size */ struct kmem_cache_node *node[MAX_NUMNODES];
};
3.4 struct kmem_cache中有哪些域是需要关注到的呢?
3.4.1 node
struct kmem_cache_node *node[MAX_NUMNODES];
这里面MAX_NUMNODES定义如下:
#define MAX_NUMNODES (1 << NODES_SHIFT)
那么NODES_SHIFT又是如何定义的呢?
#ifdef CONFIG_NODES_SHIFT
#define NODES_SHIFT CONFIG_NODES_SHIFT
#else
#define NODES_SHIFT 0
#endif
如果定义了CONFIG_NODES_SHIFT,那么NODES_SHIFT就等于CONFIG_NODES_SHIFT的值;
如果未定义CONFIG_NODES_SHIFT,那么NODES_SHIFT就等于0;
假设未定义CONFIG_NODES_SHIFT,那么MAX_NUMNODES就等于1,也就是只有一个kmem_cache_node节点.
3.4.2 cpu_slab
struct kmem_cache_cpu __percpu *cpu_slab;
表示每个cpu都具有一个这个的结构来描述当前slab的情况
__percpu是什么?
# define __percpu __attribute__((noderef, address_space()))
__percpu表示一种特性,是用来修饰变量的.noderef指定这个变量必须是有效的,address_space(3)则指定变量所在的地址空间为3,也就是cpu空间.作用就是保证每个cpu都有这个变量的副本
3.4.3 size
unsigned int size; /* The size of an object including meta data */
表示包含元数据的一个object的大小
3.4.4 object_size
unsigned int object_size;/* The size of an object without meta data */
表示不包含元数据的一个object的大小
3.4.5 offset
unsigned int offset; /* Free pointer offset. */
表示空闲指针的偏移量
3.5 __ro_after_init是什么东西?
#define __ro_after_init __attribute__((__section__(".data..ro_after_init")))
这是一个宏,定义在include/linux/cache.h中,被用来标记初始化之后只读的内容
这里面涉及到一个段.data..ro_after_init,可以在include/asm-generic/vmlinux.lds.h中找到
#ifndef RO_AFTER_INIT_DATA
#define RO_AFTER_INIT_DATA \
__start_ro_after_init = .; \
*(.data..ro_after_init) \
__end_ro_after_init = .;
#endif
4. 如何填充kmalloc_caches数组的呢?
start_kernel()-> (init/main.c)
mm_init()-> (init/main.c)
kmem_cache_init()-> (mm/slub.c)
create_kmalloc_caches()-> (mm/slab_common.c)
new_kamalloc_cache()-> (mm/slab_common.c)
create_kmalloc_cache()-> (mm/slab_common.c)
从源码中可以得知kmalloc_caches数组由create_kmalloc_cache()填充每一个数组中的元素
5. slub中支持的object的大小范围是多少?
每个kmalloc_caches中的元素会使用结构体kmem_cache中的域size和objsize来指定slab中每个object的大小,object的大小从全局常量结构体数组kmalloc_info中获取
const struct kmalloc_info_struct kmalloc_info[] __initconst = {
{NULL, }, {"kmalloc-96", },
{"kmalloc-192", }, {"kmalloc-8", },
{"kmalloc-16", }, {"kmalloc-32", },
{"kmalloc-64", }, {"kmalloc-128", },
{"kmalloc-256", }, {"kmalloc-512", },
{"kmalloc-1024", }, {"kmalloc-2048", },
{"kmalloc-4096", }, {"kmalloc-8192", },
{"kmalloc-16384", }, {"kmalloc-32768", },
{"kmalloc-65536", }, {"kmalloc-131072", },
{"kmalloc-262144", }, {"kmalloc-524288", },
{"kmalloc-1048576", }, {"kmalloc-2097152", },
{"kmalloc-4194304", }, {"kmalloc-8388608", },
{"kmalloc-16777216", }, {"kmalloc-33554432", },
{"kmalloc-67108864", }
};
从数组中的最后一个元素可以获知支持的最大object的大小为2^26=64MiB,但是从以下代码分析:
void __init create_kmalloc_caches(slab_flags_t flags)
{
int i; for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++) {
if (!kmalloc_caches[i])
new_kmalloc_cache(i, flags);
可得:
kmalloc_caches数组中仅下标为KMALLOC_SHIFT_LOW到KMALLOC_SHIFT_HIGH的元素才被初始化,
也就是从3->13支持的最小object大小为2^3=8字节,最大object大小为2^13=8KiB,说明kmalloc_caches数组的前三个元素并没有被初始化,仅初始化数组的后面11个元素.
从以上分析可得slub支持的最大object的大小为页面大小的两倍(PAGE_SIZE*2),页面大小为4KiB,那么最大object的大小为4KiB * 2 = 8KiB
分析linux内核中的slub内存管理算法的更多相关文章
- Linux内核中常用的数据结构和算法(转)
知乎链接:https://zhuanlan.zhihu.com/p/58087261 Linux内核代码中广泛使用了数据结构和算法,其中最常用的两个是链表和红黑树. 链表 Linux内核代码大量使用了 ...
- linux内核中的C语言常规算法(前提:你的编译器要支持typeof和type)
学过C语言的伙伴都知道,曾经比较两个数,输出最大或最小的一个,或者是比较三个数,输出最大或者最小的那个,又或是两个数交换,又或是绝对值等等,其实这些算法在linux内核中通通都有实现,以下的代码是我从 ...
- Linux内核入门到放弃-内存管理-《深入Linux内核架构》笔记
概述 内存管理的实现涵盖了许多领域: 内存中的物理内存页管理 分配大块内存的伙伴系统 分配较小内存块的slab.slub和slob分配器 分配非连续内存块的vmalloc机制 进程的地址空间 在IA- ...
- Linux内核设计笔记12——内存管理
内存管理学习笔记 页 页是内核管理内存的基本单位,内存管理单元(MMU,管理内存并把虚拟地址转化为物理地址的硬件)通常以页为单位进行处理,从虚拟内存的角度看,页就是最小单位. struct page{ ...
- 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业
1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...
- linux内核(四)内存管理单元MMU
1,基本概念 一个程序运行时没必要全部都同时装入内存,只需要把当前需要运行的部分装入内存即可,这样就使得一个大程序可以在较小的内存中运行,也使得内存中可以同时装入更多的程序并发执行,从用户角度看,该系 ...
- Linux内核中的有关Page的算法
static inline int get_order(unsigned long size) { int order; size = (size-1) >> (PAGE_SHIFT-1) ...
- Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制
Linux中的Buffer Cache和Page Cache echo 3 > /proc/sys/vm/drop_caches Slab内存管理机制 SLUB内存管理机制 http://w ...
- Linux内核中的GPIO系统之(3):pin controller driver代码分析
一.前言 对于一个嵌入式软件工程师,我们的软件模块经常和硬件打交道,pin control subsystem也不例外,被它驱动的硬件叫做pin controller(一般ARM soc的datash ...
随机推荐
- pandas1
https://www.cnblogs.com/nxld/p/6058591.html
- Distribution(F题)---第八届河南省程序设计大赛
Description One day , Wang and Dong in the Dubai desert expedition, discovered an ancient castle. Fo ...
- Python开发【笔记】:加锁的最佳方案
避开死锁 代码程序中,尽量要避免死锁的产生,下面分析常见的线程锁使用方式 :注:只有同一把锁才会产生互斥 1.常见的死锁方式(加锁时程序报错,锁未释放): import time import thr ...
- 理解CopyOnWriteArrayList
CopyOnWriteArrayList,顾名思义,Write的时候总是要Copy,也就是说对于任何可变的操作(add.set.remove)都是伴随复制这个动作的 A thread-safe var ...
- 订阅号助手App发布 手机也能管理公众号了
盼着许久的微信订阅号助手app终于发布了!“ 微信团队发布「订阅号助手」App,支持公众号运营者在手机上发表内容.查看和回复消息.管理已关注用户和帐号.暂时只支持iOS平台,Android平台敬请期待 ...
- linux下面发布80端口的服务
1:linux下面发布端口号为80 的服务,要在root用户下面发布.否则提示权限不够 2:在普通用户下面配置的java环境,在root用户下面不可用. 解决方法:2.1 要使用source /et ...
- mount –o remount,rw /
mount –o remount,rw / 重新挂载为已经挂载了的文件系统(以读写权限挂载),需要注意的是,挂载点必须是一个已经存在的目录,这个目录可以不为空.一般用于此目录下的文件为ro权限,需要临 ...
- hdu1305Immediate Decodability(字典树)
这题看是否 这题能A是侥幸,解决的办法是先存一下输入的字符串,进行排序. Problem Description An encoding of a set of symbols is said to ...
- 什么是anaconda【转载】
转自:https://zhidao.baidu.com/question/525102108723657245.html https://zhidao.baidu.com/question/62475 ...
- 蒙特卡洛模拟(Monte Carlo simulation)
1.蒙特卡罗模拟简介 蒙特卡罗模拟,也叫统计模拟,这个术语是二战时期美国物理学家Metropolis执行曼哈顿计划的过程中提出来的,其基本思想很早以前就被人们所发现和利用.早在17世纪,人们就知道用事 ...