分析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 ...
随机推荐
- 新购买的vps应该做的几件事情
1. 修改root密码 passwd root 2.新建用户 useradd vinentguo 3.配置免密码登陆 .使用新建用户登陆vps. mkdir ~/.ssh/ch ...
- 网站优化不等于搜索引擎优化SEO
对于SEO相信搞网络营销的人基本上都知道这个名词,英文全称为search engine optimization,中文一般叫搜索引擎优化,也有的叫搜索引擎定位(Search Engine Positi ...
- 完美解决onchange不能实时的监听
我们大家都知道onchange有时候很不好用,因为onchange事件是离开焦点后才会被触发,而不是实时去监听! 那么oninput()事件和onpropertychange()完美的解决了问题:(o ...
- 洛谷P1967 货车运输 [noip2013] 图论
正解:kruskal+LCA 解题报告: 哇真实心痛了...明明都没多少时间了我居然耗了一个上午+一个中午在上面?哭死辽我QAQ果然菜是原罪QAQ 然后这题,我先港下60pts做法趴?话说其实我觉得我 ...
- 【HTML5】初识HTML5
HTML5 简介 HTML5是HTML最新的修订版本,2014年10月由万维网联盟(W3C)完成标准制定. HTML5的设计目的是为了在移动设备上支持多媒体. HTML5 简单易学. HTML5 是下 ...
- idong常用js总结
1.判断屏幕高度 $(document).ready(function() { $("#left").height($(window).height()); $(&qu ...
- 看懂Oracle执行计划、表连接方式
看懂Oracle执行计划 原文:https://www.cnblogs.com/Dreamer-1/p/6076440.html 最近一直在跟Oracle打交道,从最初的一脸懵逼到现在的略有所知,也 ...
- 2.深度学习中的batch_size的理解
Batch_Size(批尺寸)是机器学习中一个重要参数,涉及诸多矛盾,下面逐一展开. 首先,为什么需要有 Batch_Size 这个参数? Batch 的选择,首先决定的是下降的方向.如果数据集比较小 ...
- 发现《深入理解C++11》中扩展的friend代码的错误
目前在总结现代C++的新特性,看了<深入理解C++11>这本书. 今天看到扩展的friend语法这一节,遇到了问题.本节电子版内容参见:https://book.2cto.com/2013 ...
- python 循环队列的实现
最近在做一个东西的时候发现需要用到循环队列,实现先进先出(FIFO),不断往里面添加数据,当达到某个限定值时,最先进去的出去,然后再添加.之后需要对队列里面的内容进行一个筛选,作其他处理.首先我想到了 ...