第12章 内存管理

内核不支持简单快捷的内存分配方式。

一、页

内核把无力页作为内存管理的基本单位。内存管理单元(MMU,管理内存并把虚拟地址转换为物理地址的硬件)通常以页为单元进行处理。体系结构不同,页大小不尽相同。大多数32位体系结构支持4KB的页,64位支持8KB的页。

物理页的结构体:

struct page {
  unsigned long          flags;//页的状态
  atomic_t               _count;//引用计数
  atomic_t               _mapcount;
  unsigned long          private;
  struct address_space   *mapping;
  pgoff_t                index;
  struct                 list_head;
  void                   *virtual;//页的虚拟地址
};

page结构与物理页相关,而并非与虚拟页相关。

二、区

内核使用区对具有相似特性的页进行分组。Linux主要使用四种区:

  • ZONE_DMA:包含的页用来执行DMA(直接内存访问)操作
  • ZONE_DMA32:类似ZONE_DMA,但只能被32位设备访问
  • ZONE_NORMAL:包含能正常映射的页
  • ZONE_HIGHEM:高端内存,其中的页并不能永久地映射到内核地址空间

除了ZONE_HIGHEM,其余的内存就是低端内存。


image.png

Linux把系统的页划分为区,形成不通的内存池,以根据用途进行分配。区的划分并没有任何物理意义,只不过是内核为了管理页而采取的一种逻辑上的分组。分配可以从一个或多个区获取页,但不可能同时从两个区分配。

三、获得页

内核提供了一种请求内存的底层机制,并提供了对它进行访问的几个接口,以页为单位进行分配:


image.png

alloc_pages分配的是连续的物理页,可以通过void * page_address(struct page *page);把物理页转化为逻辑地址。

四、kmalloc

void * kmalloc(size_t size, gft_t flags);

kmalloc以字节为单位进行分配,分配的内存区在物理上是连续的。

gft_t标志可分为:

  • 行为修饰符:表示内核应该如何分配所需的内存
  • 区修饰符:表示从哪儿分配内存
  • 类型修饰符:组合了行为修饰符和区修饰符
image.png
void kfree(const void *ptr);

释放kmalloc分配的内存块。kfree(NULL)是安全的。

五、vmalloc

vmalloc与kmalloc类似,但vmalloc分配的内存虚拟地址是连续的,而物理地址则无需连续。

大多数情况下,只有硬件设备需要得到物理地址连续的内存。在很多体系结构上,硬件设备存在于内存管理单元之外,不理解虚拟地址,因此硬件设备用的内存区都必须是物理上连续。仅供软件使用的内存块就可以使用只有虚拟地址连续的内存块。

void * vmalloc(unsigned long size);//分配
void vfree(const void *addr);//释放

以上两个函数都可能休眠,因此不能从中断上下文进行调用,也不能从其他不允许阻塞的情况下进行调用。

六、slab层

slab层把不同对象划分为高速缓存组,其中每个高速缓存组都存放不同类型的对象。每种对象对应一个高速缓存。

高速缓存又划分为一个或多个slab,slab由一个或多个物理上连续的页组成。每个slab都包含一些对象成员,处于满、部分满或空三种状态之一。当内核的某一部分需要一个新的对象时,先从部分满的slab中进行分配。如果没有部分满的slab,就从空的slab中进行分配。如果没有空的slab,就要创建一个slab。

image.png
//创建新的高速缓存:
struct kmem_cache * kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *));
//撤销高速缓存:
int kmem_cache_destroy(struct kmem_cache *cachep);

//获取对象
void * kmem_cache_alloc(struct kmem_cache *cachep, gft_t flags);
//释放对象
void kmem_cache_free(struct kmem_cache *cachep, void *objp);

七、在栈上的静态分配

内核栈小且固定。每个进程的内核栈大小既依赖体系结构,也与编译时的选项有关。历史上每个进程都有两页内核栈(中断处理程序与被中断进程共享一个内核栈),但2.6内核引入一个单页内核栈,这样中断处理程序就使用中断栈了。

八、高端内存的映射

高端内存中的页不能永久地映射到内核地址空间上,一旦这些页被分配,就必须映射到内核的逻辑地址空间上。

//永久映射:
void *kmap(struct page *page);
void kunmap(struct page *page);


//临时映射,不会阻塞
void *kmap_atomic(struct page *page, enum km_type type);
void kunmap_atomic(void *kvaddr, enum km_type type);

九、每个CPU的分配

一般来说,每个CPU的数据存放在一个数组中,数组中每一项对应着系统上一个存在的处理器,按当前处理器号确定这个数组的当前元素。

十、新的每个CPU接口

编译时:

//定义
DEFINE_PER_CPU(type, name);
//声明
DECLARE_PER_CPU(type, name);

//操作变量例程
get_cpu_var(name)//会禁止抢占
put_cpu_var(name)//重新激活抢占

per_cpu(name, cpu)//不禁止内核抢占,也不提供任何形式的锁保护

运行时:

void *alloc_percpu(type);
void *__alloc_percpu(size_t size, size_t align);

void free_percpu(const void *);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • 内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己来解决(用户空间的内存错误可以抛给内核来解决)...
    leon4ever阅读 930评论 0 1
  • 内存管理 在内核中分配内存不像在其他地方分配内存那么容易。造成这种局面的因素很多,根本原因是内核本身不能像用户空间...
    大雄good阅读 401评论 0 1
  • 本文以32位机器为准,串讲一些内存管理的知识点。 1. 虚拟地址、物理地址、逻辑地址、线性地址 虚拟地址又叫线性地...
    linux服务器开发阅读 2,048评论 0 0
  • 内存管理 内存管理包含: 物理内存管理; 虚拟内存管理; 两者的映射 除了内存管理模块, 其他都使用虚拟地址(包括...
    西山薄凉阅读 751评论 0 2
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,513评论 16 22