SLUB的引入及举例说明

article/2025/11/10 2:34:51

我们都知道Buddy分配器是按照页的单位分配的(Buddy系统分配器实现),如果我们需要分配几十个字节,几百个字节的时候,就需要用到SLAB分配器。

SLAB分配器专门是针对小内存分配而设计的,比如我们驱动中常见的Kmalloc分配器就是通过SLAB分配器分配的内存。

而SLAB分配器在linux系统中三种具体的实现:SLAB,SLUB,SLOB。目前内核代码中默认的SLAB分配器为SLUB算法。至于为啥不用SLAB大家可以网上看看资料,所以我们重点分析SLUB分配器的实现。

 

SLUB的原理是:

  • SLUB的内存是从Buddy拿来的,是按照页的单位从Buddy拿过来。
  • SLUB分配器会对从Buddy拿来的内存做二次分配,分配成每个小块,叫做object
  • 每个SLUB都有一个名字,比如Kmalloc-128,当我们通过Kmalloc申请内存100字节的时候,就会去Kmalloc-128的slab里面去申请
  • 当我们内存使用完毕后,需要将申请的100字节内存还给Kmalloc-128的slab的。
  • 所以当我们再次申请同样的大小内存的时候就去对应的SLAB缓冲池去申请就行,可以提供效率。

cat /proc/slabinfo节点就可以看见系统中存在的slab信息


kmalloc-8192         274    304   8192    4    8 : tunables    0    0    0 : slabdata     76     76      0
kmalloc-4096         546    568   4096    8    8 : tunables    0    0    0 : slabdata     71     71      0
kmalloc-2048        1292   1360   2048   16    8 : tunables    0    0    0 : slabdata     85     85      0
kmalloc-1024        2134   2336   1024   32    8 : tunables    0    0    0 : slabdata     73     73      0
kmalloc-512         3648   3648    512   32    4 : tunables    0    0    0 : slabdata    114    114      0
kmalloc-256         2000   2784    256   32    2 : tunables    0    0    0 : slabdata     87     87      0
kmalloc-192         4894   5124    192   21    1 : tunables    0    0    0 : slabdata    244    244      0
kmalloc-128         3360   3360    128   32    1 : tunables    0    0    0 : slabdata    105    105      0
kmalloc-96         24906  24906     96   42    1 : tunables    0    0    0 : slabdata    593    593      0
kmalloc-64         84800  84800     64   64    1 : tunables    0    0    0 : slabdata   1325   1325      0
kmalloc-32         19456  19456     32  128    1 : tunables    0    0    0 : slabdata    152    152      0
kmalloc-16         12544  12544     16  256    1 : tunables    0    0    0 : slabdata     49     49      0
kmalloc-8          11264  11264      8  512    1 : tunables    0    0    0 : slabdata     22     22      0
kmem_cache_node      576    576     64   64    1 : tunables    0    0    0 : slabdata      9      9      0
kmem_cache           294    294    384   21    2 : tunables    0    0    0 : slabdata     14     14      0

我们通过自己创建一个新的slab,带大家走进SLUB。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mm.h>static struct kmem_cache* slub_test;struct student{int age;int score;
};int slub_test_create_kmem(void)
{int ret = -1;slub_test = kmem_cache_create("slub_test", sizeof(struct student), 0, 0, NULL);if(slub_test != NULL){printk("slub_test create success!\n");ret=0;}return ret;
}static int __init slub_test_init(void)
{int ret;printk("slub_test kernel module init\n");ret = slub_test_create_kmem();return 0;
}static void __exit slub_test_exit(void)
{printk("slub_test kernel module exit\n");kmem_cache_destroy(slub_test);
}module_init(slub_test_init);
module_exit(slub_test_exit);

此例子申请了一个名为slub_test的slub,我们编译为模块了。当我们插入此模块的时候,就会在/proc/slabinfo下生成一个slub_test的名字的slab

/ # cat /proc/slabinfo | grep "slub_test"
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
slub_test              0            0          8          512           1        : tunables    0          0            0        : slabdata      0               0          0

这个是插入模块后,出来的结果。而上面这些都是什么意思呢?接着分析各个字段啥意思,我们不按照顺序解释

  • name: slub_test代表我们这个slab的名字叫slub_test
  • pagesperslab: 意思是每一个slab需要几个page,可以看到名为slub_test的slab需要一个page,也就是4K。其实就是从buddy拿了一个order为0的一个页
  • objsize: 代表的是每一个object的大小,我们传入的结构体sizeof(struct student)的大小就为8
  • objperslab: 代表的一个就是一个slab中有多少个object,通过计算是512个。

注意:如果机器开启的SLUB_DEBUG选项,有可能都不是整除的,因为一个object中存在了一些debug调试区域

接着我们从我们创建的slab中申请一个object,目前我们名字slub_test的slab中是没有Object的。当通过kmem_cache_alloc去申请一个object的时候,就会从buddy去那一页,然后计算好各个各个object之间的联系,取出一个object给我们使用。上面kmem_alloc_create只是创建了一个slab,里面还没有真正的分配object的。

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/gfp.h>static struct kmem_cache* slub_test;struct student{int age;int score;
};struct student* zhangsan;int slub_test_create_kmem(void)
{int ret = -1;slub_test = kmem_cache_create("slub_test", sizeof(struct student), 0, 0, NULL);if(slub_test != NULL){printk("slub_test create success!\n");ret=0;}zhangsan = kmem_cache_alloc(slub_test, GFP_KERNEL);if(zhangsan != NULL){printk("alloc object success!\n");ret = 0;}return ret;
}static int __init slub_test_init(void)
{int ret;printk("slub_test kernel module init\n");ret = slub_test_create_kmem();return 0;
}static void __exit slub_test_exit(void)
{printk("slub_test kernel module exit\n");kmem_cache_free(slub_test,zhangsan);kmem_cache_destroy(slub_test);
}module_init(slub_test_init);
module_exit(slub_test_exit);

这时候再次看看/proc/slabinfo下的结果

/proc/slabinfo | grep "slub_test"
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
slub_test            512            512        8            512         1        : tunables     0         0           0          : slabdata      1             1          0

可以看到数值有所变化:

  • num_objs: 就是代表objects的最大个数
  • active_objs:从代码中得出结果,如下
for_each_kmem_cache_node(s, node, n) {nr_slabs += node_nr_slabs(n);nr_objs += node_nr_objs(n);nr_free += count_partial(n, count_free);
}sinfo->active_objs = nr_objs - nr_free;
sinfo->num_objs = nr_objs;
sinfo->active_slabs = nr_slabs;
sinfo->num_slabs = nr_slabs;
sinfo->objects_per_slab = oo_objects(s->oo);
sinfo->cache_order = oo_order(s->oo);

active_objects等于nr_objs - nr_free,nr_free的值是通过count_free计算出来的。free代表的意思是总共的object减去使用的inuse的。但是slab刚创建的时候insue等于object的

#ifdef CONFIG_SLUB_DEBUG
static int count_free(struct page *page)
{return page->objects - page->inuse;
}static inline unsigned long node_nr_objs(struct kmem_cache_node *n)
{return atomic_long_read(&n->total_objects);
}
#endif /* CONFIG_SLUB_DEBUG */page->inuse = page->objects;
page->frozen = 1;

这里的意思大概是inuse代表已经用完的,那slab肯定会使用完的,所以一开始inuse就等于object的数量的。

原理就是上图的样子:slab从buddy拿到一个order为0的内存,也就是一页,然后把这一页称为名为slub_test的slab,然后把这一页分成很多小的object的。

当我们使用的时候就从slab中获取一个object使用,用完了在归还给slab管理即可。


http://chatgpt.dhexx.cn/article/RGrEkUKW.shtml

相关文章

电信光猫改桥接模式

如果只是改桥接 可以试试下面这两个地址&#xff1a;http://192.168.1.1/bridge_route.gchhttp://192.168.1.1:8080/bridge_route.gch 转载于:https://www.cnblogs.com/Devopser/p/11257535.html

电信光猫改桥接还在苦苦破解超级密码吗?

电信光猫路由改桥接&#xff0c;不同的地区有不通的方法。比较幸运的地区和终端&#xff0c;有通用的超级密码。但是不幸的地区&#xff0c;就需要通过破解这个超级密码。我就属于比较不幸的地区&#xff0c;遇到不幸的终端&#xff1a;天翼网关TEWA-708G。然后按照网上大神的破…

获取电信光猫TEWA-600超级管理密码,修改电信光猫为桥接模式

文章转载&#xff1a;玩转盒子 前些年各地运营商响应国家政策&#xff0c;光进铜退小区宽带由网线入户改成光缆入户&#xff0c;这样必须用光猫把光信号转换成电信号。我用的是中国电信的宽带&#xff0c;2017年我们小区也进行了网络改造&#xff0c;网线入户变成了光缆入户。…

友华PT921G光猫破解获取超级密码和更改桥接模式

获取超级密码 1.登陆光猫管理地址192.168.1.1 2.打开新的窗口输入&#xff1a;http://192.168.1.1/romfile.cfg ,就能下载到配置文件 3.用记事本打开romfile.cfg&#xff0c;点击编辑–>查找–>输入telecomadmin->点击查找下一个 4.查找到username“telecomadmin”,而…

为了改桥接,我决定破解中兴F450G V2光猫

还记得我之前买了个猫棒来替换光猫么&#xff1f;用了一个来月&#xff0c;发现这玩意真的不稳定&#xff0c;短则几分钟长则一两天它必定自己重启一次&#xff0c;导致我的网络时不时就会断线。这玩意不好使&#xff0c;我也没有别的光猫&#xff0c;只好找电信装维师傅给我改…

大话设计模式-桥接模式

使用场景&#xff1a;桥接模式的核心意图就是将这些实现独立出来&#xff0c;让它们各自地变化。这就使得每种实现的变化不会影响其他实现&#xff0c;从而达到应对变化的目的。 多用聚合&#xff0c;少用继承 1. 手机软件抽象类、通讯录类、游戏类 package com.hj.designPat…

电信光猫/烽火HG6543c1光猫超级密码获取改桥接模式( 中国电信浙江公司定制天翼网关3.0)

第一步&#xff1a;开telnet 浏览器网址栏输入&#xff1a;192.168.1.1:8080/cgi-bin/telnetenable.cgi?telnetenable1 第二步&#xff1a;使用pytty软件登入光猫 &#xff08;Putty软件下载&#xff1a;https://download.csdn.net/download/qq_34885669/12098009&#xff0…

保姆级-光猫改桥接-路由拨号-openwrt端口转发-阿里云DNS域名解析访问家中设备

准备&#xff1a; 1.公网ip&#xff08;江苏省电信&#xff0c;电话1分钟解决&#xff09; 2.域名(最好备案了) 3.路由器(我的是红米AC2100刷openwrt&#xff0c;重点路由器要有动态dns服务的功能&#xff0c;端口转发功能什么路由器都有) 往期教程 路由器固件刷写 红米AC210…

单臂路由 光猫桥接 一根网线复用

由于弱电箱太小&#xff0c; 二级路由拨号只能放客厅里。 这就导致其他房间无法上网了。 下面是单臂路由设置方法&#xff0c; 光猫桥接的端口下的设备&#xff0c;同样可以上网。 充分利用光猫端口。 前提&#xff1a; 光猫需要超级密码 二级路由固件为 openwrt ​​​​​

光猫桥接模式路由器拨号成功 端口映射失败的原因

路由器拨号成功&#xff0c;光猫必须是桥接模式。 光猫从路由模式设置为桥接模式的操作过程: 在浏览器地址栏中输入光猫的地址192.168.1.1&#xff0c; 进入光猫的登陆界面&#xff0c;输入超级用户名和密码&#xff0c; 用户&#xff1a;CMCCAdmin(或telecomadmin &#xff0…

电信网关改造无线打印服务器,电信天翼网关路由改桥接流程

大家好&#xff0c;好多网友要求我发一份网关路由改桥接的流程&#xff0c;由于平日工作太忙&#xff0c;更新点有慢&#xff0c;以后会多多分享平日工作中碰到的一些关于网络的各种问题。 路由改桥接首先准备以下两样。 1.网关一台(不管是四口还是二口都可以) 2.光猫超级密码&…

DDNS之光猫改桥接

相信有很多小伙伴在折腾远程开机的时候&#xff0c;都遇到了这样一个问题&#xff1a; 在成功实现了局域网唤醒之后&#xff0c;无论怎么设置DDNS、端口映射都没办法实现广域网唤醒。 究竟是什么一个原因导致的呢&#xff1f;亿元程序员今天就给大家讲解其中一个原因&#xff…

电信中兴f452光猫路由改桥接最简单的方式,亲自体验成功。

家里的光猫是中兴f452&#xff0c;默认是路由模式&#xff0c;改为桥接由路由器拨号&#xff0c;过程如下&#xff0c;验证成功。前提是去电信营业厅申请内网IP改公网IP&#xff0c;申请通过后再进行如下操作。 1、网上的方法很多都是用超级用户密码登陆&#xff0c;也就是用户…

宽带开启ipv6的方法(包含光猫改桥接和光猫改桥接后访问其管理界面以及路由器拨号)

本文将介绍移动宽带如何开启ipv6 你为什么需要ipv6&#xff1f; 关于v4 v6地址个数的差别不再赘述&#xff0c;主要介绍对于家庭用户的实际意义 开启ipv6之后&#xff0c;种子下载文件时&#xff0c;可以从只有ipv6的设备获取资源&#xff0c;增加了资源个数&#xff0c;赚钱宝…

光猫桥接后宽带降速问题解决

文章目录 一、背景二、解决方案三、升级款改动四、排查经历 一、背景 光猫桥接使用路由器拨号后宽带降速到原来的一半。 条件&#xff1a; 1、新办的电信宽带2、光猫桥接&#xff0c;路由器拨号3、光猫10Gbps接口&#xff0c;路由器1Gbps接口 现象&#xff1a; 光猫路由器…

路由器连接光猫用桥接模式好还是用路由模式好?路由器桥接模式vs路由模式

许多家庭网络中的上网设备即有光猫又有路由器&#xff0c;那么光猫和路由器在家庭网络中各起什么作用呢&#xff1f;一般如何搭配使用可以满足资源利用最大化呢&#xff1f;怎么样搭配能让网络利用效率最高呢&#xff1f; 下面来解答以上问题&#xff0c;首先说说光猫和路由器…

光猫桥接服务器无响应,解决光猫改为桥接后无法再次访问的问题

换了一个千兆光猫&#xff0c;型号是PT632。最近在研究IPv6&#xff0c;不停的折腾光猫的WAN口连接模式(Route和Bridge)。 大概的设备结构&#xff1a;光猫(PT632)→路由器(网件R8000)→下端设备 发现一个问题&#xff1a; 光猫使用Route模式(路由器模式)时&#xff0c;光猫进行…

光猫改桥接之后连接路由器上网的设备不能访问光猫的解决方法

因为群晖需要外网访问&#xff0c;将自购的路由器改为拨号上网&#xff0c;光猫设置为桥接模式。 但这种情况下&#xff0c;因为路由的网段 (我的是 192.168.3.x) 和光猫的网段 (电信&#xff0c;默认 192.168.1.x) 不同&#xff0c;此时不能通过 192.168.1.1 网址来连接光猫&a…

电信光猫桥接+ML固件路由器实现ipv6网站访问

一、引言 本文干货满满&#xff0c;请警慎食用。众所周知&#xff0c;ipv6商用已经很长时间了&#xff0c;奈何自家的设备一直不能访问ipv6网站&#xff0c;本着不折腾不死心的态度&#xff0c;有了如下的折腾之旅。 二、方法 ① 环境准备&#xff1a;博主家里的电信光猫品牌是…

光猫改桥接,手机如何访问光猫后台,只要一根网线就可以了

光猫改桥接之后一般有四种方法可以访问光猫后台&#xff0c;一、电脑用网线直连光猫的LAN口&#xff0c;然后设置好对应IP&#xff1b;二、光猫自带WiFi功能的&#xff0c;就直接开启WiFi&#xff0c;连接对应的WiFi&#xff1b;三、路由器的WAN口支持双模式&#xff0c;即可以…