Kmalloc申请内存源码分析
再上一节了解了SLUB是如何申请一个object的,其中涉及了从当前的freelist申请,以及kmem_cache_cpu->partital链表申请,以及到最后的kmem_cache_cpu→node中申请,如果上述三个步骤都没有申请到的话,就会重新创建一个新的slab,然后设置好freelist的指针,返回object使用。
本节我们重点分析下Kmalloc的实现,其实在驱动中大家使用最多的就是用kmalloc申请内存,kmalloc申请的内存大小都普遍比较小,比较快,而且物理地址和虚拟地址是线性映射的,因为kmalloc拿到的内存是从noraml zone获取的。关于zone的知识我们后面有机会说。
直接上代码,去看下Kmalloc的实现。
* The @flags argument may be one of:** %GFP_USER - Allocate memory on behalf of user. May sleep.** %GFP_KERNEL - Allocate normal kernel ram. May sleep.** %GFP_ATOMIC - Allocation will not sleep. May use emergency pools.* For example, use this inside interrupt handlers.** %GFP_HIGHUSER - Allocate pages from high memory.** %GFP_NOIO - Do not do any I/O at all while trying to get memory.** %GFP_NOFS - Do not make any fs calls while trying to get memory.** %GFP_NOWAIT - Allocation will not sleep.** %__GFP_THISNODE - Allocate node-local memory only.
static __always_inline void *kmalloc(size_t size, gfp_t flags)
{if (__builtin_constant_p(size)) {if (size > KMALLOC_MAX_CACHE_SIZE)return kmalloc_large(size, flags);
#ifndef CONFIG_SLOBif (!(flags & GFP_DMA)) {unsigned int index = kmalloc_index(size);if (!index)return ZERO_SIZE_PTR;return kmem_cache_alloc_trace(kmalloc_caches[index],flags, size);}
#endif}return __kmalloc(size, flags);
}
- 申请的时候会传递2个参数,第一个参数就是要申请的大小,第二个参数就是申请内存的一些flag,比如常见的GFP_KERNEL
- 大家也看下注释都有哪些flag,这些flag都代表啥意思,是否可以睡眠,是否是原子操作等
- __builtin_constant_p 是gcc的一个属性,我们不用理会,直接看_kmalloc的实现。
#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)
#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)
#define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT)
#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM)
#define GFP_NOIO (__GFP_RECLAIM)
#define GFP_NOFS (__GFP_RECLAIM | __GFP_IO)
#define GFP_USER (__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
#define GFP_DMA __GFP_DMA
#define GFP_DMA32 __GFP_DMA32
- 大家常用的应该有GFP_KERNEL,它是由三个flag组成的。__GFP_RECLAIM=可回收,__GFP_IO=有IO的操作,有IO的操作就可能会导致sleep
- GFP_ATOMIC: 它也是有三个组成,__GFP_HIGH=高优先级等等
- 大家有兴趣可以看看Gfp.h文件的注释就清楚了。
void *__kmalloc(size_t size, gfp_t flags)
{struct kmem_cache *s;void *ret;if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))return kmalloc_large(size, flags);s = kmalloc_slab(size, flags);if (unlikely(ZERO_OR_NULL_PTR(s)))return s;ret = slab_alloc(s, flags, _RET_IP_);trace_kmalloc(_RET_IP_, ret, size, s->size, flags);kasan_kmalloc(s, ret, size, flags);return ret;
}
- 如果size大于Kmalloc申请的最大size(4K),则调用kmalloc_large去申请。也就是申请太大的内存,就不用直接找我slab了,直接去找buddy拿吧
- 通过kmalloc_slab去获取对应大小的kmem_cache缓冲池
- 调用slab_alloc从对应的kmem_cache中去申请一个object,返回去即可。
- 所以说来说去,还是从slab去申请内存,里面的内存就和上一节的内存一样了。
如果size大于4K,每个平台,每个版本,每个slab的实现大小不一样。
static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
{unsigned int order = get_order(size);return kmalloc_order_trace(size, flags, order);
}void *kmalloc_order(size_t size, gfp_t flags, unsigned int order)
{void *ret;struct page *page;flags |= __GFP_COMP;page = alloc_pages(flags, order);ret = page ? page_address(page) : NULL;kmemleak_alloc(ret, size, 1, flags);kasan_kmalloc_large(ret, size, flags);return ret;
}
很直接,如果大小太大,不用找我slab了,我是小内存申请分配器,反正我的内存也是从buddy拿的,你直接去找buddy拿对应order的页。
struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
{unsigned int index;if (size <= 192) {if (!size)return ZERO_SIZE_PTR;index = size_index[size_index_elem(size)];} else {if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) {WARN_ON(1);return NULL;}index = fls(size - 1);}#ifdef CONFIG_ZONE_DMAif (unlikely((flags & GFP_DMA)))return kmalloc_dma_caches[index];#endifreturn kmalloc_caches[index];
}
- 根据size计算出一个index,此index就是kmalloc_caches数组下标,此数据中有对应很多个大小的kmalloc_cache缓冲池
- 如果申请的内存是从DMA ZONE去申请,就从kmalloc_dma_caches中去找对应的kmalloc_cache缓冲池
static void __init new_kmalloc_cache(int idx, slab_flags_t flags)
{kmalloc_caches[idx] = create_kmalloc_cache(kmalloc_info[idx].name,kmalloc_info[idx].size, flags, 0,kmalloc_info[idx].size);
}
kmalloc_caches数组是通过kmalloc_info数组里面的信息决定的。
const struct kmalloc_info_struct kmalloc_info[] __initconst = {{NULL, 0}, {"kmalloc-96", 96},{"kmalloc-192", 192}, {"kmalloc-8", 8},{"kmalloc-16", 16}, {"kmalloc-32", 32},{"kmalloc-64", 64}, {"kmalloc-128", 128},{"kmalloc-256", 256}, {"kmalloc-512", 512},{"kmalloc-1024", 1024}, {"kmalloc-2048", 2048},{"kmalloc-4096", 4096}, {"kmalloc-8192", 8192},{"kmalloc-16384", 16384}, {"kmalloc-32768", 32768},{"kmalloc-65536", 65536}, {"kmalloc-131072", 131072},{"kmalloc-262144", 262144}, {"kmalloc-524288", 524288},{"kmalloc-1048576", 1048576}, {"kmalloc-2097152", 2097152},{"kmalloc-4194304", 4194304}, {"kmalloc-8388608", 8388608},{"kmalloc-16777216", 16777216}, {"kmalloc-33554432", 33554432},{"kmalloc-67108864", 67108864}
};
可以看到,系统中专门为kmalloc申请了一系列大小的kmem_cache缓冲区,平常用到的大小都会有涉及的。
大家也可以去/proc/slabinfo下去查看对应的kmalloc信息
root:/ # cat /proc/slabinfo | grep "kmalloc"
kmalloc-8192 644 663 8704 3 8 : tunables 0 0 0 : slabdata 221 221 0
kmalloc-4096 2250 2254 4608 7 8 : tunables 0 0 0 : slabdata 322 322 0
kmalloc-2048 6767 6780 2560 12 8 : tunables 0 0 0 : slabdata 565 565 0
kmalloc-1024 2374 2436 1536 21 8 : tunables 0 0 0 : slabdata 116 116 0
kmalloc-512 7034 7296 1024 32 8 : tunables 0 0 0 : slabdata 228 228 0
kmalloc-256 17285 17640 768 21 4 : tunables 0 0 0 : slabdata 840 840 0
kmalloc-128 301624 303775 640 25 4 : tunables 0 0 0 : slabdata 12151 12151 0
Kmalloc申请内存源码分析相关推荐
- 一文给你解决linux内存源码分析- SLUB分配器概述(超详细)
SLUB和SLAB的区别 首先为什么要说slub分配器,内核里小内存分配一共有三种,SLAB/SLUB/SLOB,slub分配器是slab分配器的进化版,而slob是一种精简的小内存分配算法,主要用于 ...
- linux内存源码分析 - 内存压缩(同步关系)
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 最近在看内存回收,内存回收在进行同步的一些情况非常复杂,然后就想,不会内存压缩的页面迁移过程中的同步关系也 ...
- linux内核源码剖析 博客,【Linux内存源码分析】页面迁移
页面迁移其实是伙伴管理算法中的一部分,鉴于其特殊性,特地另行分析.它是2007年的时候,2.6.24内核版本开发时,新增碎片减少策略(the fragmentation reduction strat ...
- Linux brk(),mmap()系统调用源码分析3:brk()的内存申请流程
Linux brk(),mmap()系统调用源码分析 brk()的内存申请流程 荣涛 2021年4月30日 内核版本:linux-5.10.13 注释版代码:https://github.com/Rt ...
- ceph bluestore 源码分析:ceph-osd内存查看方式及控制源码分析
文章目录 内存查看 内存控制 内存控制源码分析 通过gperftools接口获取osd进程实际内存 动态设置cache大小 动态调整cache比例 trim释放内存 本文通过对ceph-osd内存查看 ...
- Nginx源码分析:核心数据结构ngx_cycle_t与内存池概述
nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> 核心数据结构与内存池概述 在Nginx中的核心数据结构就是ngx_cycle_t结构,在初始 ...
- Python3.5源码分析-内存管理
Python3源码分析 本文环境python3.5.2. 参考书籍<<Python源码剖析>> python官网 Python3的内存管理概述 python提供了对内存的垃圾收 ...
- java直接内存为什么快_直接内存与 JVM 源码分析
直接内存(堆外内存) 直接内存有一种叫法,堆外内存. 直接内存(堆外内存)指的是 Java 应用程序通过直接方式从操作系统中申请的内存.这个差别与之前的堆.栈.方法区,那些内存都是经过了虚拟化.所以严 ...
- Spark源码分析之九:内存管理模型
Spark是现在很流行的一个基于内存的分布式计算框架,既然是基于内存,那么自然而然的,内存的管理就是Spark存储管理的重中之重了.那么,Spark究竟采用什么样的内存管理模型呢?本文就为大家揭开Sp ...
- nginx源码分析—内存池结构ngx_pool_t及内存管理
本博客( http://blog.csdn.net/livelylittlefish)贴出作者(阿波)相关研究.学习内容所做的笔记,欢迎广大朋友指正! Content 0.序 1.内存池结构 1.1 ...
最新文章
- Driver for device rausb0 has been compiled with version 22
- java-number
- 厉害了,Servlet3的异步处理机制
- 【Android】实现页面跳转
- 任务寄存器TR:GDT、LDT、IDT、TR、TSS之间的关系
- Android开发笔记(一百六十九)利用BottomNavigationView实现底部标签栏
- 关闭IE窗口时执行事件
- web前端js上传文件
- SVNAdmin - 好用的开源SVN管理系统
- 【脑图制作】万彩脑图大师教程 | 修改主题样式
- 最新列表!国内外核心期刊数据库收录范围汇总介绍
- maya中英文对照_Maya 2018 英汉速查手册
- 非常有用的 windows CMD 命令大全
- 联想拯救者笔记本(R720、y7000、y7000p)安装ubuntu无法使用无线网卡
- matlab视频工具箱下载,MATLAB robotics tools工具箱下载安装
- html5开发一个音乐播放器,HTML5开发学习(1):使用aduio标签打造音乐播放器
- JAVA 基因牛的繁殖
- LCD编程显示像素点
- Linux内核中的软中断、tasklet和工作队列详解
- 版本测试准入准出的一些标准