linux中的 slab/slob/slub

linux中的 slab/slob/slub很久很久以 bai 前 一个叫做 MarkHemment 的哥儿们 du 写了 Slab 在接下来的一些年里 zhi 其他人对 Slab 进行了完善 dao 一年半以前 SLOB 问世了 SLOB 的目标是针对嵌入式系统的 主要是适用于那些内存非常有限的系统 比如 32MB 以下的内存 它不太注重 largesmp 系统 虽然最近在这方面有一些小的改进 几个月之前 SLUB 闪亮登场 它基本上属于对 Slab 的重设计 redesign 但是代码更少 并且能更好的适应 largeNUMA 系统 SLUB 被很认为是 Slab 和 Slob 的取代者 大

———————————————————————————————————————————————————————-

小内存的问题算是解决了,但还有一个大内存的问题:用伙伴系统分配10 x 4KB的数据时,会去16 x 4KB的空闲列表里面去找(这样得到的物理内存是连续的),但很有可能系统里面有内存,但是伙伴系统分配不出来,因为他们被分割成小的片段。那么,vmalloc就是要用这些碎片来拼凑出一个大内存,相当于收集一些“边角料”,组装成一个成品后“出售”:

————————————————————————————————————————————————————————-

1.linux 内核 内存管理 slub算法 (一) 原理

https://blog.csdn.net/lukuen/article/details/

图简单明了

2.宋牧春: 多图详解Linux内存分配器slub

https://blog.csdn.net/juS3Ve/article/details/?utm_source=blogxgwz7

http://www.wowotech.net/memory_management/426.html

1.2结合看

Linux-3.14.12内存管理笔记【SLUB分配算法(1)】

http://blog.chinaunix.net/uid-26859697-id-5472929.html

linux中的 slab/slob/slub

3.伙伴系统之伙伴系统概述–Linux内存管理(十五)

https://blog.csdn.net/GerryLee93/article/details//#22-%E6%9C%80%E5%A4%A7%E9%98%B6max_order%E4%B8%8Eforce_max_zoneorder%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9

 

————————————————————————————————————————————————————————-

我用RH9做主机linux usb器件驱动,因为是高速,所以必须一次传完,循环收会出错,因此要开辟2.56M的内存空间,而用__get_free_pages(GFP_KERNEL,9)最多只能分配2M内存,当用__get_free_pages(GFP_KERNEL,10)准备分配4M时出错,从而不能分配2M以上内存,不知如何解决,请教高手!谢谢

#ifndef CONFIG_FORCE_MAX_ZONEORDER #define MAX_ORDER 11 #else #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER #endif 

可以考虑下vmalloc()函数,不过该函数分配的内存物理上是不连续的,所以不能用来做DMA之类的操作!
具体使用,自己看内核的例子!

另外对于__get_free_pages()能分配的最大的内存,是可以通过重新配置,编译内核来扩大的! 具体配置选项好像是
CONFIG_FORCE_MAX_ZONEORDER!如果内核是你自己可以控制的,建议重编译内核,然后用__get_free_pages()这个函数!

Good Luck!
 














要做DMA操作吗? 如果不是的话,可以用vmalloc

linux 技术交流群  欢迎大家的加入

up

另外,vmalloc你试过没有,也许可以满足你的需求!

————————————————————————————————————————————————————————-

在Linux内核中, kmalloc能够分配的最大连续内存为2的(MAX_ORDER-1)次方个page(参见alloc_pages函数,     “if (unlikely(order >= MAX_ORDER))        return NULL;”), page的大小一般是4K bytes, MAX_ORDER缺省定义为11, 所以如果不修改内核, kmalloc能够分配的最大连续内存一般是4M bytes.

内核中获取4M以上大内存的方法有三种:

  1.修改MAX_ORDER, 重新编译内核 (CONFIG_FORCE_MAX_ZONEORDER=13)

  2.内核启动选型传递”mem=”参数, 如”mem=80M“, 预留部分内存; 然后通过request_mem_regionioremap_nocache将预留的内存映射到模块中. 需要修改内核启动参数, 无需重新编译内核. 但这种方法不支持x86架构, 只支持ARM, PowerPC等非x86架构.

(bootargs = “earlycon clk_ignore_unused consoleblank=0 cma=1600M uio_pdrv_genirq.of_id=generic-uio cpuidle.off=1″;)

  3.在start_kernel中mem_init函数之前调用alloc_boot_mem函数预分配大块内存, 需要重新编译内核.

 

  在不重新编译内核的前提下, x86架构下内核中只能获取到最大4M的连续内存, 或者使用vmalloc获取4M以上的非连续内存.

 

  而且, 无论是kmalloc还是vmalloc, 分配的内存越大, 失败的可能性越大系统启动后分配内存的时间越早(此时空闲内存越多, 分部也越规律), 成功的可能性越大

————————————————————————————————————————————————————————

Linux内核内存管理算法Buddy和Slab

有了前两节的学习相信读者已经知道CPU所有的操作都是建立在虚拟地址上处理(这里的虚拟地址分为内核态虚拟地址和用户态虚拟地址),CPU看到的内存管理都是对page的管理,接下来我们看一下用来管理page的经典算法–Buddy。

 

Buddy分配算法

 

 

linux中的 slab/slob/slub

 

假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框。这个时候,在这段内存上不能找到连续的5个空闲的页框,就会去另一段内存上去寻找5个连续的页框,这样子,久而久之就形成了页框的浪费。为了避免出现这种情况,Linux内核中引入了伙伴系统算法(Buddy system)。把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍,如图:

 

 

linux中的 slab/slob/slub

 

 

假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块,如果没有,就去512个页框的链表中找,找到了则将页框块分为2个256个页框的块,一个分配给应用,另外一个移到256个页框的链表中。如果512个页框的链表中仍没有空闲块,继续向1024个页框的链表查找,如果仍然没有,则返回错误。页框块在释放时,会主动将两个连续的页框块合并为一个较大的页框块。

从上面可以知道Buddy算法一直在对页框做拆开合并拆开合并的动作。Buddy算法牛逼就牛逼在运用了世界上任何正整数都可以由2^n的和组成。这也是Buddy算法管理空闲页表的本质。 空闲内存的信息我们可以通过以下命令获取:

 

linux中的 slab/slob/slub

 

也可以通过echo m > /proc/sysrq-trigger来观察buddy状态,与/proc/buddyinfo的信息是一致的:

 

 

linux中的 slab/slob/slub

 

 

CMA

 

细心的读者或许会发现当Buddy算法对内存拆拆合合的过程中会造成碎片化的现象,以至于内存后来没有了大块的连续内存,全是小块内存。当然这对应用程序是不影响的(前面我们讲过用页表可以把不连续的物理地址在虚拟地址上连续起来),但是内核态就没有办法获取大块连续的内存(比如DMA, Camera, GPU都需要大块物理地址连续的内存)。

在嵌入式设备中一般用CMA来解决上述的问题。CMA的全称是contiguous memory allocator, 其工作原理是:预留一段的内存给驱动使用,但当驱动不用的时候,CMA区域可以分配给用户进程用作匿名内存或者页缓存。而当驱动需要使用时,就将进程占用的内存通过回收或者迁移的方式将之前占用的预留内存腾出来,供驱动使用。

 

Slab

 

在Linux中,伙伴系统(buddy system)是以页为单位管理和分配内存。但是现实的需求却以字节为单位,假如我们需要申请20Bytes,总不能分配一页吧!那岂不是严重浪费内存。那么该如何分配呢?slab分配器就应运而生了,专为小内存分配而生。slab分配器分配内存以Byte为单位。但是slab分配器并没有脱离伙伴系统,而是基于伙伴系统分配的大内存进一步细分成小内存分配。我们先来看一张图:

 

 

linux中的 slab/slob/slub

 

kmem_cache是一个cache_chain的链表,描述了一个高速缓存,每个高速缓存包含了一个slabs的列表,这通常是一段连续的内存块。存在3种slab:

  • slabs_full(完全分配的slab)
  • slabs_partial(部分分配的slab)
  • slabs_empty(空slab,或者没有对象被分配)。

 

slab是slab分配器的最小单位,在实现上一个slab有一个货多个连续的物理页组成(通常只有一页)。单个slab可以在slab链表之间移动,例如如果一个半满slab被分配了对象后变满了,就要从slabs_partial中被删除,同时插入到slabs_full中去。

 

为了进一步解释,这里举个例子来说明,用struct kmem_cache结构描述的一段内存就称作一个slab缓存池。一个slab缓存池就像是一箱牛奶,一箱牛奶中有很多瓶牛奶,每瓶牛奶就是一个object。分配内存的时候,就相当于从牛奶箱中拿一瓶。总有拿完的一天。当箱子空的时候,你就需要去超市再买一箱回来。超市就相当于partial链表,超市存储着很多箱牛奶。如果超市也卖完了,自然就要从厂家进货,然后出售给你。厂家就相当于伙伴系统。

 

可以通过下面命令查看slab缓存的信息:

 

linux中的 slab/slob/slub

 

 

总结

从内存DDR分为不同的ZONE,到CPU访问的Page通过页表来映射ZONE,再到通过Buddy算法和Slab算法对这些Page进行管理,我们应该可以从感官的角度理解了下图:

 

 

linux中的 slab/slob/slub

 

用户/内核 API名称 物理连续? 大小限制 单位 场景
用户空间 malloc/calloc/realloc/free  不保证  堆申请  字节 calloc初始化为0;realloc改变内存大小。
alloca    栈申请  字节 向栈申请内存
mmap/munmap       将文件利用虚拟内存技术映射到内存中去。
brk、sbrk        虚拟内存到内存的映射。sbrk(0)返回program break地址,sbrk调整对的大小。

间    

  vmalloc/vfree

虚拟连续

物理不定

 vmalloc区大小限制

 页

VMALLOC区域

可能睡眠,不能从中断上下文中调用,或其他不允许阻塞情况下调用。

VMALLOC区域vmalloc_start~vmalloc_end之间,vmalloc比kmalloc慢,适用于分配大内存。

  slab kmalloc/kcalloc/krealloc/kfree 物理连续

64B-4MB

(随slab而变)

 2^order字节

Normal区域

大小有限,不如vmalloc/malloc大。

最大/小值由KMALLOC_MIN_SIZE/KMALLOC_SHIFT_MAX,对应64B/4MB。

从/proc/slabinfo中的kmalloc-xxxx中分配,建立在kmem_cache_create基础之上。

kmem_cache_create 物理连续 64B-4MB

字节大小,需对齐

Normal区域

便于固定大小数据的频繁分配和释放,分配时从缓存池中获取地址,释放时也不一定真正释放内存。通过slab进行管理。

伙伴系统  __get_free_page/__get_free_pages 物理连续  4MB(1024页)

Normal区域

 __get_free_pages基于alloc_pages,但是限定不能使用HIGHMEM。
 alloc_page/alloc_pages/free_pages 物理连续 4MB 

Normal/Vmalloc都可 

 CONFIG_FORCE_MAX_ZONEORDER定义了最大页面数2^11,一次能分配到的最大页面数是1024。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/207603.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午1:30
下一篇 2026年3月19日 下午1:30


相关推荐

  • Java——闰年判断

    Java——闰年判断目录任务1、闰年判断(一)编程实现方法一、采用并列式多分支结构评定成绩等级方法二、采用嵌套式多分支结构评定成绩等级方法三、采用延拓式多分支结构评定成绩等级方法四、采用开关式多分支结构评定成绩等级任务1、闰年判断什么是闰年?有两种情况:能被4整除但是不能被100整除;能被400整除解决闰年判断问题,涉及三种运算:算术运算、关系运算、逻辑运算第一种闰年情况:year%4==0&&year%100!=0第二种闰年情况:year%400==0(一)编程实现

    2022年7月17日
    17
  • java watchdog_Watchdog实现分析

    java watchdog_Watchdog实现分析系统启动过程图:Framework层所有的Service都是运行在SystemServer进程中;SystemServer进程是由Zygote进程创建。SystemServer进程启动分两个过程init1创建Service和进程状态对象;init2创建Framework层的Service,将其加入到ServiceManager中,最后启动launcher;Android提供了Watchdog类,用…

    2025年6月17日
    14
  • linux读写锁_共享内存读写锁

    linux读写锁_共享内存读写锁一、读写锁是什么?读写锁其实还是一种锁,是给一段临界区代码加锁,但是此加锁是在进行写操作的时候才会互斥,而在进行读的时候是可以共享的进行访问临界区的ps:读写锁本质上是一种自旋锁二、为什么需要读写锁?有时候,在多线程中,有一些公共数据修改的机会比较少,而读的机会却是非常多的,此公共数据的操作基本都是读,如果每次操作都给此段代码加锁,太浪费时间了而且也很浪费资源…

    2022年8月12日
    9
  • 基于Speex的声学回声消除[通俗易懂]

    基于Speex的声学回声消除[通俗易懂]所谓声学回声消除,是为了解决VoIP(网络电话)中这样一个问题:即A与B进行通话,A端有麦克风和扬声器分别用来采集A的声音和播放B的声音,B端有麦克风和扬声器分别用来采集B的声音和播放A的声音,很明显,由于声音传播的特性,A端的麦克风在采集A的声音的同时,也采集到了A端扬声器播放的来自B的声音,也就是A端采集到的声音是一个混合的声音,这个声音通过网络发给B时,B就不仅能听到A的声音,也能听见B前几

    2025年5月24日
    8
  • 版本号命名规则_文件版本号命名规则

    版本号命名规则_文件版本号命名规则版本号的格式为X.Y.Z(又称Major.Minor.Patch),递增的规则为:X表示主版本号,当API的兼容性变化时,X需递增。Y表示次版本号,当增加功能时(不影响API的兼容性),Y需递增。Z表示修订号,当做Bug修复时(不影响API的兼容性),Z需递增。详细的规则如下:X,Y,Z必须为非负整数,且不得包含前导零,必须按数值递增,如1….

    2025年10月25日
    7
  • OpenManus安装教程

    OpenManus安装教程

    2026年3月15日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号