主要介绍kmalloc和kfree代码流程,侧重kmalloc和kfree流程中锁使用规则,会引用到cpuset,mempolicy(内存策略),numa相关知识。如果读起来比较困难可以参考另一篇随笔《内存管理-slab[原理]》

kmalloc

kmalloc原型如下:

 // /include/linuxslab_def.h
static __always_inline void *kmalloc(size_t size, gfp_t flags)

函数功能:从内核态内存中申请size字节大小的内存段返回给系统,内核态内存指的是DMA区和NORMAL区,即kmalloc不能申请HIGHTMEM区的内存(其实再64位系统中不存在HIGHTMEM区)

结合代码流程将kmalloc流程分成两个阶段,下分会详细介绍这两个阶段的内容

kmalloc第一个阶段

第一个阶段函数调用路径如图(1)

图(1)

这个阶段主要完成的功能如下:

A.根据入参size和gfp_t选择合适的kmam_cache数据结构。具体如下:size的范围是1到2的(MAX_ORDER + PAGE_SHIFT - 1)次方,2的MAX_ORDER-1次方是buddy一次alloc_pages所能申请到的最大连续物理页数(大多数系统是2^10次方),2的PAGE_SHIFT次方是每个物理页框的大小。(宗上:得到一个结论,一个slab描述符最多经过一次alloc_pages获取内存,一次free_pages释放内存,并且slab下管理的最大内存段上限是2的(MAX_ORDER + PAGE_SHIFT - 1)次方.)根据size我们只能选定特定长度的kmem_cache,但《内存管理-slab[原理]》一文中提到每一个长度的对象对应的kmem_cache有两个,一个用来管理NORMAL区或者DMA区内存,两外一个专门管理DMA区内存,因此还需要第二个参数,才能选到唯一的kmem_cache

B.根据入参flags从1中通过size筛选出来的两个kmem_cache中选择一个。具体如下:如果flags中GFP_DMA位被值位,就选择专门用来管理DMA区内存的kmem_cache.否者则选择另一个用来管理NORMAL区或者DMA区内存的kmem_cache.(gfp具体参数可以通过如下命令过滤内核源码看到大概情况:grep -r '[^_]*kmalloc[[:space:]]('|sed -nr 's/.*,[[:space:]]*(GFP.*)$/\1/gp')

C.利用local_irq_save关闭cpu的本地中断.关中断原因:接下来会访问到kmem_cache以及其下的slab描述符等数据结构,而kmalloc是允许在中断上下文调用的,所以必须关中断来对中断上下文同步。这里特意用irq_save和irq_restore来关中断,而不是用irq_disable和irq_enable来关中断原因是kmalloc允许在关中断后调用。

上面代码经过1->4和2->3就功能来说完全相同,就是完成上面的A和B两个功能。但是为什么要分两个路径?原因:1->4这个路径在通过sizeof(XXX)的形式给出入参size的情况下会提高些性能;其实只要size入参是编译器能够计算出来的常量时,都走1->4这个路径,否者走2->3这个路径(注意kmalloc原型时inline)。路径5这里完成功能C,即关中断,调用__do_cache_alloc函数,__do_cache_alloc返回后,开中断,然后根据GFP_ZERO|flags结果来判断是否对返回的对象做memset(0,...)的操作。

到此介绍完了第一阶段的函数流程,宗上:第一阶段主要动作按时序如下:选择唯一一个kmem_cache->关中断->调用__do_cache_alloc来分配对象->开中断->根据GFP_ZERO|flags结果判断是否要对分配到的对象做memset(0,...)的操作。

kmalloc第二个阶段

通过第一个阶段得出结论:实际分配对象的操作是在__do_cache_alloc中来完成的。(注意__cache_alloc和__do_cache_alloc这两个函数的名字不是偶然的,在内核编码中经常出现XXXX和__do_XXXX这种组合,其中XXXX是__do_XXXX的包裹函数,XXXX中一般用来处理同步:比如关中断,关抢占,获取自旋锁,或者检查入参合法性等等,而实际的工作时在__do_XXXX中完成)

slab分配要实现的目标:

1.如果kmalloc入参flags显示有GFP_THISNODE:只能在当前cpu的本地节点分配内存

2.如果kmalloc入参flags没有GFP_THISNODE且在中断上下文:首先在当前cpu的本地节点分配对象,如果本地节点分配失败,则依次在系统中所有的节点上分配

3.如果kmalloc入参flag没有GFP_THISNODE且不在中断上下文且进程设置了cpuset或者mempolicy,限制只能在某个或某些node节点上分配内存:1.首先根据cpuset和mempolicy来选择一个节点,在这个节点上分配对象。2.如果所选择的这个节点分配不到对象则依次fallback到cpuset和mempolicy所允许的节点集合中分配对象,如果上面集合中的所有节点都分配不到对象,则尝试第二次(这里不是完全的重新尝试,类时重新尝试一次),如果第二次分配失败,则返回失败。

4.如果kmalloc参flag没有GFP_THISNODE且不在中断上下文且没有设置cpuset或mempolicy,

如图2是第二个阶段的关键点函数以及调用路径,总的来说需要注意两点:

α:其中1,2,3是并行关系,即__do_cache_alloc先调用1,1成功分配到对象则直接返回对象(成功),否者调用,如果成功分配到对象则直接返回(成功),否者调用,如果成功分配到对象则直接返回(成功),否者返回NULL(失败)

β:路径1和2最后都汇聚到___cache_alloc_node函数,而调用路径8->9出现了递归调用,找到这个递归调用结束的条件,是理解这部分代码的关键。

图(2)

alternate_node_alloc,___cache_alloc_node, ___cache_alloc的原型如下,结合图(2)1->4和2最后都汇聚到___cache_alloc_node函数,因此这个函数是kmalloc的核心。下面我们分别介绍1,2,3三个路径上函数完成的功能。

 //:/mm/slab.c 三个函数的flags字段都是由kmalloc透传过来,没有做过任何改变
static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags);
static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,int nodeid);
static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags);

路径1

由于路径1经过alternate_node_alloc后和路径2汇聚,路径1讨论主要集中在函数__do_cache_alloc调用alternate_node_alloc的时机,以及alternate_node_alloc完成的工作。

路径1主要是为了处理cpuset和mempolicy。首先,cpuset和mempolicy针对内核slab内存分配都是用来限制进程上下文分配的内存,不会限制中断(包括软中断和硬中断)上下文的内存分配。

内存管理-slab[代码]的更多相关文章

  1. linux内存管理--slab及其代码解析

    Linux内核使用了源自于 Solaris 的一种方法,但是这种方法在嵌入式系统中已经使用了很长时间了,它是将内存作为对象按照大小进行分配,被称为slab高速缓存. 内存管理的目标是提供一种方法,为实 ...

  2. 内存管理-slab[原理]

    前言 主要讲解原理,基于2.6.32版本内核源码.本文整体思路:先由简单内存模型逐渐演进到当下通用服务器面对的内存模型,讨论每一个内存模型下slab设计需要解决的问题. 历史简介 linux内核运行需 ...

  3. Linux内存管理 - slab分配器和kmalloc

    本文目的在于分析Linux内存管理机制的slab分配器.内核版本为2.6.31.1. SLAB分配器 内核需要经常分配内存,我们在内核中最常用的分配内存的方式就是kmalloc了.前面讲过的伙伴系统只 ...

  4. OC MRC之set方法内存管理(代码分析)

    // // main.m // 03-set方法的内存管理 // // Created by apple on 13-8-9. // Copyright (c) 2013年 itcast. All r ...

  5. 内存管理-buddy[代码]

    基于2.6.32内核源码分析 首选内存区和gfp描述符关系运算 64位系统默认没有开启CONFIG_HIGHMEM选项,因此只有4个内存区DMA(0),DMA32(1),NORMAL(2),MOVAB ...

  6. iOS性能优化之内存管理:Analyze、Leaks、Allocations的使用和案例代码

    最近接了个小任务,和公司的iOS小伙伴们分享下instruments的具体使用,于是有了这篇博客...性能优化是一个很大的话题,这里讨论的主要是内存泄露部分. 一. 一些相关概念 很多人应该比较了解这 ...

  7. 【深入理解Linux内核架构】第3章:内存管理

    3.1 概述 内存管理涵盖了许多领域: 内存中物理内存页的管理: 分配大块内存的伙伴系统: 分配小块内存的slab.slub.slob分配器: 分配非连续内存块的vmalloc机制: 进程的地址空间. ...

  8. iOS 内存管理

    一 . 内存管理 包括内存分配 和 内存清除 1.内存管理的范围 :人和继承于NSObject类的对象都需要进行内存管理,任何非对象类型的对象(基本数据类型 如 int char float doub ...

  9. objective-c 语法快速过(6)内存管理原理

    内存管理基本原理(最重要) 移动设备的内存极其有限(iphone 4内存512M),每个app所能占用的内存是有限制的(几十兆而已). 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不 ...

随机推荐

  1. 2018面向对象程序设计(Java)第16周学习指导及要求

    2018面向对象程序设计(Java)第16周学习指导及要求(2018.12.13-2018.12.16)   学习目标 (1) 掌握线程概念: (2) 掌握线程创建的两种技术: (3) 理解和掌握线程 ...

  2. Codeforces Round #500 (Div. 2) [based on EJOI]

    Codeforces Round #500 (Div. 2) [based on EJOI] https://codeforces.com/contest/1013 A #include<bit ...

  3. 结构体指offsetof宏详细解析

    1.#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)     (include/linux/stddef.h) ...

  4. FortiGate部分用户上网慢,丢包严重

    1.现状: 如图,出口internet有2条联通线路分别为liant_218和liant_61,在防火墙上使用WAN LLB,基于源IP: 2.现象: 使用liant_218的用户上网正常,使用lia ...

  5. Python开发——数据类型【字典】

    字典的定义 # Python语言中唯一的类型映射 # 键与值之间用“:”分开 # 项与项之间用“,”分开 person = {"name":"yuan",&qu ...

  6. js data日期初始化的5种方法

    var objDate=new Date([arguments list]);  参数形式有以下5种: 1)new Date("month dd,yyyy hh:mm:ss");  ...

  7. linux下面重启apche 与mysql服务

    1.service httpd restart 重启apache 2.service mysqld restart 重启mysql 开启与停止换成start与stop即可

  8. 微服务架构day01

    1.微服务架构的基本概念 分布式:将一个项目模块化 区分为多个子项目(自己理解:将业务逻辑层和数据库访问层独立化   通过rpc远程调用(rpc框架  springCould  httpCliend ...

  9. 关于webconfig的记录恢复本

    <?xml version="1.0"?> <!--注意: 除了手动编辑此文件以外,您还可以使用 Web 管理工具来配置应用程序的设置.可以使用 Visual S ...

  10. (PMP)第8章-----项目质量管理

    过程质量管理,成果质量的管理 戴明理论:PDCA,戴明环 朱兰理论:质量规划,质量控制,质量改进,朱兰三部曲 克鲁斯比理论:零缺陷,质量免费 石川理论:质量圈,因果图,质量管理七大工具:核对表,帕累托 ...