内存学习(八):块分配器1

简介: 内存学习(八):块分配器1

一、块分配器概述

前面我们知道了页分配器,但是有一定的使用场景不让人满意,因此这里又引伸出了块分配器,这个内存的分配方式有更小的粒度。

SLAB分配器的作用不仅仅是分配小块内存,更重要的作用是针对经常分配和释放的对象充当缓存。

SLAB分配器的核心思想是:为每种对象类型创建一个内存缓存,每个内存缓存由多个大块(slab,原意是大块的混凝土)组成,一个大块是一个或多个连续的物理页,每个大块包含多个对象。

SLAB采用了面向对象的思想,基于对象类型管理内存,每种对象被划分为一类,例如进程描述符(task_struct)是一个类,每个进程描述符实例是一个对象。内存缓存的组成如图3.21所示。

SLAB分配器在某些情况下表现不太好,所以Linux内核提供了两个改进的块分配器。

  • (1)在配备了大量物理内存的大型计算机上,SLAB分配器的管理数据结构的内存开销比较大,所以设计了SLUB分配器。
  • (2)在小内存的嵌入式设备上,SLAB分配器的代码太多、太复杂,所以设计了一个精简的SLOB分配器。SLOB是“Simple List Of Blocks”的缩写,意思是简单的块链表。目前SLUB分配器已成为默认的块分配器。

二、编程接口

3种块分配器提供了统一的编程接口。

为了方便使用,块分配器在初始化的时候创建了一些通用的内存缓存,对象的长度大多数是2n字节,从普通区域分配页的内存缓存的名称是“kmalloc-”(size是对象的长度),从DMA区域分配页的内存缓存的名称是“dma-kmalloc-”,执行命令“cat /proc/slabinfo”可以看到这些通用的内存缓存。

通用的内存缓存的编程接口如下。

(1)分配内存。

void *kmalloc(size_t size, gfp_t flags);
  • size:需要的内存长度。
  • flags:传给页分配器的分配标志位,当内存缓存没有空闲对象,向页分配器请求分配页的时候使用这个分配标志位。

块分配器找到一个合适的通用内存缓存:对象的长度刚好大于或等于请求的内存长度,然后从这个内存缓存分配对象。如果分配成功,返回对象的地址,否则返回空指针。

(2)重新分配内存。

void *krealloc(const void *p, size_t new_size, gfp_t flags);
  • p:需要重新分配内存的对象。
  • new_size:新的长度。
  • flags:传给页分配器的标志位。

根据新的长度为对象重新分配内存,如果分配成功,返回新的地址,否则返回空指针。

(3)释放内存。

void kfree(const void *objp);
  • objp:kmalloc()返回的对象的地址。

这里提一个思考题:kfree函数怎么知道对象属于哪个通用的内存缓存?后面解答。

特殊接口

1-创建专用的内存缓存

使用通用的内存缓存的缺点是:块分配器需要找到一个对象的长度刚好大于或等于请求的内存长度的通用内存缓存,如果请求的内存长度和内存缓存的对象长度相差很远,浪费比较大,例如申请36字节,实际分配的内存长度是64字节,浪费了28字节。

所以有时候使用者需要创建专用的内存缓存,编程接口如下。

struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,unsigned long flags, void (*ctor)(void *));
  • name:名称。
  • size:对象的长度。
  • align:对象需要对齐的数值。
  • flags:SLAB标志位。
  • ctor:对象的构造函数。

如果创建成功,返回内存缓存的地址,否则返回空指针。

2-从指定的内存缓存分配对象。

void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
  • cachep:从指定的内存缓存分配。
  • flags:传给页分配器的分配标志位,当内存缓存没有空闲对象,向页分配器请求分配页的时候使用这个分配标志位。

如果分配成功,返回对象的地址,否则返回空指针。

3-释放对象。

void kmem_cache_free(struct kmem_cache *cachep, void *objp);
  • cachep:对象所属的内存缓存。
  • objp:对象的地址。

4-销毁内存缓存。

void kmem_cache_destroy(struct kmem_cache *s);
  • s:内存缓存。

下一篇我们分别来看看块分配器的三种

参考内容《Linux内核深度解析》

目录
相关文章
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
65 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
存储 Java
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
这篇文章详细地介绍了Java对象的创建过程、内存布局、对象头的MarkWord、对象的定位方式以及对象的分配策略,并深入探讨了happens-before原则以确保多线程环境下的正确同步。
53 0
JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
|
5月前
|
NoSQL Java Redis
Redis系列学习文章分享---第十八篇(Redis原理篇--网络模型,通讯协议,内存回收)
Redis系列学习文章分享---第十八篇(Redis原理篇--网络模型,通讯协议,内存回收)
84 0
|
5月前
|
缓存 Java
《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)
《JVM由浅入深学习九】 2024-01-15》JVM由简入深学习提升分(生产项目内存飙升分析)
50 0
|
3月前
|
存储 JavaScript 前端开发
学习JavaScript 内存机制
【8月更文挑战第23天】学习JavaScript 内存机制
34 3
|
3月前
|
关系型数据库 MySQL
MySQl优化:使用 jemalloc 分配内存
MySQl优化:使用 jemalloc 分配内存
|
3月前
|
缓存 Java 编译器
Go 中的内存布局和分配原理
Go 中的内存布局和分配原理
|
4月前
|
存储 缓存 算法
(五)JVM成神路之对象内存布局、分配过程、从生至死历程、强弱软虚引用全面剖析
在上篇文章中曾详细谈到了JVM的内存区域,其中也曾提及了:Java程序运行过程中,绝大部分创建的对象都会被分配在堆空间内。而本篇文章则会站在对象实例的角度,阐述一个Java对象从生到死的历程、Java对象在内存中的布局以及对象引用类型。
126 8
|
4月前
|
NoSQL Redis C++
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
c++开发redis module问题之在复杂的Redis模块中,特别是使用第三方库或C++开发时,接管内存统计有哪些困难
|
4月前
|
Java 运维
开发与运维内存问题之在堆内存中新创建的对象通常首先分配如何解决
开发与运维内存问题之在堆内存中新创建的对象通常首先分配如何解决
24 1