kzalloc 函数详解

2023-11-06

用kzalloc申请内存的时候, 效果等同于先是用 kmalloc() 申请空间 , 然后用 memset() 来初始化 ,所有申请的元素都被初始化为 0.

/**
 * kzalloc - allocate memory. The memory is set to zero.
 * @size: how many bytes of memory are required.
 * @flags: the type of memory to allocate (see kmalloc).
 */
static inline void *kzalloc(size_t size, gfp_t flags)
{
	return kmalloc(size, flags | __GFP_ZERO);
}
kzalloc 函数是带参数调用kmalloc函数,添加的参数是或了标志位__GFP_ZERO,
void *__kmalloc(size_t size, gfp_t flags)
{
	struct kmem_cache *s;
	void *ret;

	if (unlikely(size > SLUB_MAX_SIZE))
		return kmalloc_large(size, flags);

	s = get_slab(size, flags);

	if (unlikely(ZERO_OR_NULL_PTR(s)))
		return s;

	ret = slab_alloc(s, flags, -1, _RET_IP_);

	trace_kmalloc(_RET_IP_, ret, size, s->size, flags);

	return ret;
}
这个函数调用trace_kmalloc,flags参数不变,继续往里面可以看到

static __always_inline void *slab_alloc(struct kmem_cache *s,
		gfp_t gfpflags, int node, unsigned long addr)
{
	void **object;
	struct kmem_cache_cpu *c;
	unsigned long flags;
	unsigned int objsize;

	gfpflags &= gfp_allowed_mask;

	lockdep_trace_alloc(gfpflags);
	might_sleep_if(gfpflags & __GFP_WAIT);

	if (should_failslab(s->objsize, gfpflags))
		return NULL;

	local_irq_save(flags);
	c = get_cpu_slab(s, smp_processor_id());
	objsize = c->objsize;
	if (unlikely(!c->freelist || !node_match(c, node)))

		object = __slab_alloc(s, gfpflags, node, addr, c);

	else {
		object = c->freelist;
		c->freelist = object[c->offset];
		stat(c, ALLOC_FASTPATH);
	}
	local_irq_restore(flags);

	if (unlikely((gfpflags & __GFP_ZERO) && object))
		memset(object, 0, objsize);

	kmemcheck_slab_alloc(s, gfpflags, object, c->objsize);
	kmemleak_alloc_recursive(object, objsize, 1, s->flags, gfpflags);

	return object;
}
这里主要判断两个标志,WAIT和ZERO,和本文有关的关键代码就是

if (unlikely((gfpflags & __GFP_ZERO) && object))
memset(object, 0, objsize);


到此,这个函数区别于kmalloc的地方就清楚了

kmalloc 函数详解

#include <linux/slab.h> void *kmalloc(size_t size, int flags);

给 kmalloc 的第一个参数是要分配的块的大小. 第 2 个参数, 分配标志, 非常有趣, 因为它以几个方式控制 kmalloc 的行为.

最一般使用的标志, GFP_KERNEL, 意思是这个分配((内部最终通过调用 __get_free_pages 来进行, 它是 GFP_ 前缀的来源) 代表运行在内核空间的进程而进行的. 换句话说, 这意味着调用函数是代表一个进程在执行一个系统调用. 使用 GFP_KENRL 意味着 kmalloc 能够使当前进程在少内存的情况下睡眠来等待一页. 一个使用 GFP_KERNEL 来分配内存的函数必须, 因此, 是可重入的并且不能在原子上下文中运行. 当当前进程睡眠, 内核采取正确的动作来定位一些空闲内存, 或者通过刷新缓存到磁盘或者交换出去一个用户进程的内存.

GFP_KERNEL 不一直是使用的正确分配标志; 有时 kmalloc 从一个进程的上下文的外部调用. 例如, 这类的调用可能发生在中断处理, tasklet, 和内核定时器中. 在这个情况下, 当前进程不应当被置为睡眠, 并且驱动应当使用一个 GFP_ATOMIC 标志来代替. 内核正常地试图保持一些空闲页以便来满足原子的分配. 当使用 GFP_ATOMIC 时, kmalloc 能够使用甚至最后一个空闲页. 如果这最后一个空闲页不存在, 但是, 分配失败.

其他用来代替或者增添 GFP_KERNEL 和 GFP_ATOMIC 的标志, 尽管它们 2 个涵盖大部分设备驱动的需要. 所有的标志定义在 <linux/gfp.h>, 并且每个标志用一个双下划线做前缀, 例如 __GFP_DMA. 另外, 有符号代表常常使用的标志组合; 这些缺乏前缀并且有时被称为分配优先级. 后者包括:

GFP_ATOMIC
用来从中断处理和进程上下文之外的其他代码中分配内存. 从不睡眠.
GFP_KERNEL
内核内存的正常分配. 可能睡眠.
GFP_USER
用来为用户空间页来分配内存; 它可能睡眠.
GFP_HIGHUSER
如同 GFP_USER, 但是从高端内存分配, 如果有. 高端内存在下一个子节描述.
GFP_NOIO
GFP_NOFS
这个标志功能如同 GFP_KERNEL, 但是它们增加限制到内核能做的来满足请求. 一个 GFP_NOFS 分配不允许进行任何文件系统调用, 而 GFP_NOIO 根本不允许任何 I/O 初始化. 它们主要地用在文件系统和虚拟内存代码, 那里允许一个分配睡眠, 但是递归的文件系统调用会是一个坏注意.

上面列出的这些分配标志可以是下列标志的相或来作为参数, 这些标志改变这些分配如何进行:

__GFP_DMA
这个标志要求分配在能够 DMA 的内存区. 确切的含义是平台依赖的并且在下面章节来解释.
__GFP_HIGHMEM
这个标志指示分配的内存可以位于高端内存.
__GFP_COLD
正常地, 内存分配器尽力返回"缓冲热"的页 -- 可能在处理器缓冲中找到的页. 相反, 这个标志请求一个"冷"页, 它在一段时间没被使用. 它对分配页作 DMA 读是有用的, 此时在处理器缓冲中出现是无用的.
__GFP_NOWARN
这个很少用到的标志阻止内核来发出警告(使用 printk ), 当一个分配无法满足.
__GFP_HIGH
这个标志标识了一个高优先级请求, 它被允许来消耗甚至被内核保留给紧急状况的最后的内存页.
__GFP_REPEAT
__GFP_NOFAIL
__GFP_NORETRY
这些标志修改分配器如何动作, 当它有困难满足一个分配. __GFP_REPEAT 意思是" 更尽力些尝试" 通过重复尝试 -- 但是分配可能仍然失败. __GFP_NOFAIL 标志告诉分配器不要失败; 它尽最大努力来满足要求. 使用 __GFP_NOFAIL 是强烈不推荐的; 可能从不会有有效的理由在一个设备驱动中使用它. 最后, __GFP_NORETRY 告知分配器立即放弃如果得不到请求的内存.
kmalloc 能够分配的内存块的大小有一个上限. 这个限制随着体系和内核配置选项而变化. 如果你的代码是要完全可移植, 它不能指望可以分配任何大于 128 KB. 如果你需要多于几个 KB
这方面的原因:
kmalloc并不直接从分页机制中获得空闲页面而是从slab页面分配器那儿获得需要的页面,slab的实现代码限制了最大分配的大小为128k,即131072bytes,理论上你可以通过更改slab.c中的 cache_sizes数组中的最大值使得kmalloc可以获得更大的页面数,不知道有没有甚么副效应或者没有必要这样做,因为获取较大内存的方法有很多,想必128k是经验总结后的合适值。
alloc_page( )可以分配的最大连续页面是4K
 static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) 

/* 
 * Gets optimized away by the compiler. 
 */ 
 if (order >= MAX_ORDER) 
 return NULL; 
 return _alloc_pages(gfp_mask, order); 
 } 

alloc_pages最大分配页面数为512个,则可用内存数最大为2^9*4K=2M
  




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

kzalloc 函数详解 的相关文章

  • 在 JS 中查找对象上特定值的键

    我有一个使用 lodash 生成的对象 zipObject 功能 所以我有 2 个数组 一个是位置 一个是数字 var locs Aberdeen 304 Aberystwith 109 Belfast 219 Birmingham 24
  • 为什么Java不支持结构体? (只是出于好奇)

    我知道您可以使用公共字段或其他一些解决方法 或者也许你根本不需要它们 但只是出于好奇为什么 Sun 没有考虑结构 这是一个link http www oracle com technetwork java simple 142616 htm
  • 我们可以有一个可变长度数组类型的结构元素吗? [复制]

    这个问题在这里已经有答案了 我们可以声明一个可变长度的结构元素吗 条件如下 typedef struct uint8 t No Of Employees uint8 t Employee Names No Of Employees 15 s
  • 如何在java hashset中查找并返回对象

    根据 HashSet javadoc HashSet contains 仅返回布尔值 如何在 hashSet 中 查找 对象并修改它 它不是原始数据类型 我看到 HashTable 有一个 get 方法 但我更喜欢使用该集合 您可以删除一个
  • 如何在 jQuery 中检查 null 对象

    我正在使用 jQuery 我想检查页面中是否存在某个元素 我写了以下代码 但它不起作用 if btext i null alert btext i text btext i text Branch i 如何检查元素是否存在 检查jQuery
  • 在 C 中初始化结构体的静态数组

    我正在用 C 实现一个纸牌游戏 纸牌有很多种类型 每种纸牌都有大量信息 包括一些需要单独编写与其关联的脚本的操作 给定这样的结构 并且我不确定我的语法是否适合函数指针 struct CARD int value int cost This
  • 结构中字符串的管理

    我知道字符串的长度是可变的 因此它们需要内存中的可变空间来存储 当我们在 a 中定义一个字符串项时struct the struct的大小的长度将是可变的 较旧的语言通过使用固定长度的字符串来管理此问题 但是 C 中没有办法定义固定长度的字
  • C++:初始化结构体并设置函数指针

    我正在尝试使用函数指针初始化结构 但是除非使用全局函数完成 否则我很难这样做 以下代码有效 float tester float v return 2 0f v struct MyClass Example typedef float My
  • angular.copy() 和 JSON.parse(JSON.stringify()) 之间的区别?

    有人可以解释 angular copy 和 JSON parse JSON stringify 之间的区别吗 有吗 您会推荐使用什么 angular fromJson angular toJson 与 JSON parse JSON str
  • 结构体tag和name,为什么声明为name的局部变量会编译?

    在我最近看到的一些代码中 有一个如下定义的结构 typedef struct tagMyStruct int numberOne int numberTwo MYSTRUCT 按照我的理解 tagMyStruct是新的数据类型并且MYSTR
  • 如何使对象“a == b”的比较成立? [复制]

    这个问题在这里已经有答案了 这是面试前 JavaScript 在线测试的问题之一 function F var a new F var b new F Q 如何进行比较a b to be true e g console log a b t
  • 序列化对于对象大小估计可靠吗?

    我使用序列化来估计对象使用的内存量 我已经读过this https stackoverflow com questions 426396 how much memory does a c net object use and this ht
  • C 结构体信息隐藏(不透明指针)

    我目前对 C 结构信息隐藏的概念有点困惑 这道题的背景是一个嵌入式c项目 对OOP的了解几乎为零 到目前为止 我总是在相应模块的头文件中声明我的 typedef 结构 因此每个想要使用该结构的模块都知道该结构类型 但经过 MISRA C 检
  • C++ 指针和对象实例化

    这有效 MyObject o o new MyObject 而这并不 MyObject o new MyObject Why 关键词new 返回一个指针 http msdn microsoft com en us library kewsb
  • 如何在Java中计算对象的数字年龄[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想知道Java中对象的年龄 当我们使用new关键字时 Java中用户定义的对象被创建 但是什么时候它会被销毁 是跨越JVM的perm
  • Python struct.pack() 'struct.error: bad char in struct format' 尝试保存字节顺序时

    我正在尝试打包一个字符串和字符串的长度 fmt
  • PHP 对象创建和内存使用

    一个基本的虚拟类 class foo var bar 0 function foo function boo echo memory get usage echo n foo new foo echo memory get usage ec
  • 字符串化 JavaScript 对象

    我正在寻找字符串化一个对象 我想要这样的输出 1 valeur dalebrun usager experttasp date 2013 08 20 16 41 50 2 valeur test usager experttasp date
  • 如何从 Xib 文件加载自定义 UITableViewCell?

    问题很简单 如何加载自定义UITableViewCell来自 Xib 文件 这样做可以让您使用 Interface Builder 来设计您的单元 由于内存管理问题 答案显然并不简单 这个线程 https stackoverflow com
  • C# 无法访问已释放的对象

    我正在制作一个服务器 客户端应用程序 我将服务器套接字设置为侦听 并设置 BeginAccept 方法 当我关闭服务器套接字 Socket Close 以关闭服务器时 BeginAccept 方法的异步回调方法抛出异常 我检查了异常 发现异

随机推荐

  • Redis简明教程

    Redis是啥 用Redis官方的话来说就是 Redis is an open source BSD licensed in memory data structure store used as a database cache and
  • [ROS] roscore启动失败

    版本描述 Ubuntu18 04 ROS melodic 问题描述 ROS安装完成后 出现如下错误 具体原因是因为ROS1支持的是Python2 7 而我之前将Ubuntu自带的Python升级到了3 6 所以导致了相关的错误 nnboy
  • 伺服电机与编码器

    编码器的结构域工作原理 1 透射式旋转光电编码器 2 编码器的分辨率 3 编码器的分类和特点 按照工作原理 可以分为增量式和绝对式 4 伺服电机与编码器的工作 控制器驱动电机运转 电机带着编码器旋转 编码器的反馈信号输送到控制器 可以知道
  • 大数据毕设 深度学习 大数据 股票预测系统 - python lstm

    文章目录 0 前言 1 课题意义 1 1 股票预测主流方法 2 什么是LSTM 2 1 循环神经网络 2 1 LSTM诞生 2 如何用LSTM做股票预测 2 1 算法构建流程 2 2 部分代码 3 实现效果 3 1 数据 3 2 预测结果
  • ICLR2023《Crossformer: Transformer Utilizing Cross-Dimension Dependency for Multivariate Time Series》

    这是一篇ICLR2023 top 5 论文 论文链接 https openreview net pdf id vSVLM2j9eie 代码 https github com Thinklab SJTU Crossformer 1 Multi
  • dedecms--图片的轮播

    1 直接在php加代码 引入js css文件
  • shell脚本调用另一个脚本

    两种实现方式 shell脚本直接调用另一个脚本 shell脚本新建终端并执行另一个脚本 1 shell脚本直接调用另一个脚本 shellPath sh main shell script call other shell script ec
  • mysql 字符串分割函数substring_index用法

    实现和python split 函数一样的功能 mysql用函数substring index 用法 substring index str 分隔符 第n个分隔符之前的所有字符or倒数第n个分隔符之后的所有字符 例子 select subs
  • Qt4_深入信号和槽

    信号和槽 信号和槽是Qt 编程的一个重要部分 这个机制可以在对象之间彼此并不了解的情况下将它们的行为联系起来 在前几个例程中 我们已经连接了信号和槽 声明了控件自己的信号和槽 并实现了槽函数 发送了信号 现在来更深入了解这个机制 槽和普通的
  • 【Java】【字符串】IP地址与整数的相互转换

    package itheima2 import java util Scanner public class Main public static void main String args Scanner scanner new Scan
  • MFC程序的诞生与死亡

    MFC程序的诞生与死亡 程序的诞生 Application object产生 内存于是获得配置 初值亦设立了 Afx WinMain执行AfxWinInit 后者又调用AfxInitThread 把消息队列尽量加大到96 AfxWinMai
  • django 国际化

    一 开启国际化 1 setting中默认语言改为 LANGUAGE CODE es es 2 添加中间件 django middleware locale LocaleMiddleware MIDDLEWARE CLASSES django
  • 「数字货币监管」听证会重磅来袭,无形之笼悄然降临?

    美国的国会老爷们要认真讨论数字货币的监管问题了 一个全方位的数字货币监管框架正在成型 作者 唐晗 编辑 秦晋 出品 碳链价值 ID cc value 美国国会对数字货币上瘾了 7月30日 美国参议院银行 住房和城市事务委员会将于华盛顿时间上
  • 配置wsl外网访问(实操步骤)

    介绍 wsl存在一个ip1 window存在一个ip2 ip1无法ping通与ip2处于同一网段下的ip 此种情况下 涉及到网络通信相关的开发就比较困难 本文介绍配置wsl外网的访问 操作步骤 获取wsl的ip 管理员身份在powershe
  • Jenkins安装部署与自动化部署网站实战

    1 CICD与Jenkins概述 互联网软件的开发和发布 已经形成了一套标准流程 假如把开发工作流程分为以下几个阶段 编码 构建 集成 测试 交付 部署 在上图中看到 持续集成 Continuous Integration 持续交付 Con
  • 数据结构-1

    1 2 线性结构树状结构网状结构 表 数 图 数据 数值型 非数值型 1 2 3数据类型和抽象数据类型 1 3抽象数据类型 概念小结 线性表 如果在独立函数实现的 c 文件中需要包含 stdlib h 头文件 而主函数也需要包含 stdli
  • 服务器部署Java项目详述

    前言 记录一下自己从0到1部署Java前后端项目到服务器上的过程 过程梗概 首先要先买一个服务器 一般用CentOS7 然后大概步骤是再配置一下所买的服务器环境 再安装下对应我们的Java项目所需要的一些应用程序即可 其中 Nginx是用来
  • 如何部署LVS + keepalived 负载均衡高可用集群

    目录 一 LVS架构 概念 L4和L7负载均衡的区别 keepalive故障自动切换 抢占与非抢占 二 keepalived管理LVS负载均衡器 LVS集中节点的健康检查 三 部署LVS keeplived 高可用集群 第一步 关闭防火墙和
  • Scala中 常用容器类的函数/方法

    1 foreach 迭代遍历集合中的每个元素 对每个元素进行处理 但是没有返回值 常用于打印结果数据 val ls List 1 3 5 7 9 ls foreach println 打印每个元素 ls foreach println 打印
  • kzalloc 函数详解

    用kzalloc申请内存的时候 效果等同于先是用 kmalloc 申请空间 然后用 memset 来初始化 所有申请的元素都被初始化为 0 kzalloc allocate memory The memory is set to zero