14 内核开发-slab 子系统,kmalloc、kzalloc 和 kfree

2024-04-28 22:20

本文主要是介绍14 内核开发-slab 子系统,kmalloc、kzalloc 和 kfree,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

14 内核开发-slab 子系统,kmalloc、kzalloc 和 kfree

目录

14 内核开发-slab 子系统,kmalloc、kzalloc 和 kfree

1.定义

2.内涵

3.使用示例

4.具体代码使用实践

5.注意事项

6.最佳实践

7.总结



课程简介:
Linux内核开发入门是一门旨在帮助学习者从最基本的知识开始学习Linux内核开发的入门课程。该课程旨在为对Linux内核开发感兴趣的初学者提供一个扎实的基础,让他们能够理解和参与到Linux内核的开发过程中。

课程特点
1. 入门级别:该课程专注于为初学者提供Linux内核开发的入门知识。无论你是否具有编程或操作系统的背景,该课程都将从最基本的概念和技术开始,逐步引导学习者深入了解Linux内核开发的核心原理。

2. 系统化学习:课程内容经过系统化的安排,涵盖了Linux内核的基础知识、内核模块编程、设备驱动程序开发等关键主题。学习者将逐步了解Linux内核的结构、功能和工作原理,并学习如何编写和调试内核模块和设备驱动程序。

3. 实践导向:该课程强调实践,通过丰富的实例和编程练习,帮助学习者将理论知识应用到实际的Linux内核开发中。学习者将有机会编写简单的内核模块和设备驱动程序,并通过实际的测试和调试来加深对Linux内核开发的理解。

4. 配套资源:为了帮助学习者更好地掌握课程内容,该课程提供了丰富的配套资源,包括教学文档、示例代码、实验指导和参考资料等。学习者可以根据自己的学习进度和需求,灵活地利用这些资源进行学习和实践。

无论你是计算机科学专业的学生、软件工程师还是对Linux内核开发感兴趣的爱好者,Linux内核开发入门课程都将为你提供一个扎实的学习平台,帮助你掌握Linux内核开发的基础知识,为进一步深入研究和应用Linux内核打下坚实的基础。

这一讲,主要分享如何在内核开模块开发中如何使用slab 子系统,kmalloc、kzalloc 和 kfree
来进行内存管理分配回收。


1.定义


slab、kmalloc、kzalloc 和 kfree 在 Linux 内核中都用于管理内存分配,但它们之间存在一些关键差异:

  • slab 是一个子系统,用于管理内核对象(如文件系统inode 和套接字缓冲区)的内存分配。它使用一种称为 slab 缓存的机制来减少内存碎片并提高分配和释放性能。
  • kmalloc 和 kzalloc 是函数,用于从内核堆中分配内存。kmalloc 分配的内存未初始化,而 kzalloc 分配的内存被清零。

kfree 是一个函数,用于释放先前由 kmalloc 或 kzalloc 分配的内存。
slab 与 kmalloc/kzalloc/kfree 的关系,slab 子系统与 kmalloc、kzalloc 和 kfree 函数一起工作,如下所示:

  • kmalloc 和 kzalloc 函数用于从 slab 缓存中分配对象。
  • kfree 函数用于将对象释放回 slab 缓存。

通过使用 slab 子系统,kmalloc、kzalloc 和 kfree 函数可以高效且可扩展地分配和释放内核对象内存。


2.内涵


何时使用 slab,何时使用kmalloc kzalloc ?这里提供一个简单的原则,可以参考:

应在以下情况下使用 slab 子系统:

  • 当需要为内核对象分配大量内存时。
  • 当需要高效地分配和释放内核对象时。
  • 当需要减少内存碎片时。
  • 何时使用 kmalloc/kzalloc/kfree

应在以下情况下使用 kmalloc 和 kzalloc 函数:

  • 当需要为非内核对象分配内存时。
  • 当不需要高效的内存分配和释放时。
  • 当不需要减少内存碎片时。
3.使用示例

kmalloc/kzalloc/kfree

(a)kmalloc

void kmalloc(size_t size, gfp_t flags);
其中:size:要分配的内存大小(以字节为单位)。flags:指定分配标志的标志。GFP_KERNEL:这是一个分配标志,它指示内核应从内核内存池中分配内存。GFP_KERNEL 标志是最常用的标志,它适用于大多数内核内存分配。函数的运作方式:当调用 kmalloc(1024, GFP_KERNEL); 时,内核将执行以下操作:它将在内核内存池中搜索一个大小至少为 1024 字节的空闲内存块。
如果找到一个合适的块,内核将分配该块并将其返回给调用者。
如果找不到合适的块,内核将尝试从伙伴系统中分配一个新块。伙伴系统是一种内存管理技术,它将内存划分为不同大小的块,以便有效分配和释放内存。
如果伙伴系统无法分配一个新块,内核将返回 NULL,表示分配失败。

(b)kzalloc

void kzalloc(size_t size, gfp_t flags);其中:size:要分配的内存大小(以字节为单位)。flags:指定分配标志的标志。
sizeof(struct myctx):这是要分配的内存大小,以字节为单位。在本例中,它分配一个足够大以容纳 struct myctx 结构体的内存块。GFP_KERNEL:这是一个分配标志,它指示内核应从内核内存池中分配内存。GFP_KERNEL 标志是最常用的标志,它适用于大多数内核内存分配。函数的运作方式:当调用 kzalloc(sizeof(struct myctx), GFP_KERNEL); 时,内核将执行以下操作:它将在内核内存池中搜索一个大小至少为 sizeof(struct myctx) 字节的空闲内存块。
如果找到一个合适的块,内核将分配该块,并将其初始化为零。然后,它将块返回给调用者。
如果找不到合适的块,内核将尝试从伙伴系统中分配一个新块。伙伴系统是一种内存管理技术,它将内存划分为不同大小的块,以便有效分配和释放内存。
如果伙伴系统无法分配一个新块,内核将返回 NULL,表示分配失败。

(c)kfree

void kfree(const void ptr);ptr:要释放的内存块的地址。函数的运作方式:当调用 kfree(ctx); 时,内核将执行以下操作:它将检查 ctx 是否为 NULL。如果是,函数将立即返回,没有任何操作。
内核将检查 ctx 指向的内存块是否由 kmalloc() 或 kzalloc() 分配。如果不是,函数将返回 -EINVAL 错误。
内核将查找 ctx 指向的内存块的元数据。元数据包含有关内存块大小和分配标志的信息。
内核将根据元数据中的分配标志将内存块归还给内核内存池。
内核将 ctx 设置为 NULL,以指示内存块已释放。

    
4.具体代码使用实践
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>MODULE_LICENSE("GPL");
MODULE_VERSION("0.2");static char gkptr;
struct myctx {u32 iarr[100];u64 uarr[100];char uname[128], passwd[16], config[16];
};
static struct myctx ctx;static int __init slab1_init(void)
{gkptr = kmalloc(1024, GFP_KERNEL);if (!gkptr) {WARN_ONCE(1, "kmalloc() failed!\n");goto out_fail1;}pr_info("kmalloc() succeeds, (actual KVA) ret value = %px\n", gkptr);print_hex_dump_bytes("gkptr before memset: ", DUMP_PREFIX_OFFSET, gkptr, 32);memset(gkptr, 'm', 1024);print_hex_dump_bytes(" gkptr after memset: ", DUMP_PREFIX_OFFSET, gkptr, 32);ctx = kzalloc(sizeof(struct myctx), GFP_KERNEL);if (!ctx)goto out_fail2;pr_info("context struct alloc'ed and initialized (actual KVA ret = %px)\n", ctx);print_hex_dump_bytes("ctx: ", DUMP_PREFIX_OFFSET, ctx, 32);return 0;        / success /out_fail2:kfree(gkptr);out_fail1:return -ENOMEM;
}static void __exit slab1_exit(void)
{kfree(ctx);kfree(gkptr);pr_info("freed slab memory, removed\n");
}module_init(slab1_init);
module_exit(slab1_exit);

5.注意事项

使用 slab、kmalloc、kzalloc 和 kfree 时的注意事项:

使用 slab 时,请考虑以下事项:

  1. 确保为要分配的内核对象类型创建了 slab 缓存。
  2. 仅使用 slab 缓存分配和释放内核对象。
  3. 避免为非内核对象分配 slab 缓存。
  4. 监视 slab 缓存的使用情况,以检测内存泄漏或碎片。

使用 kmalloc 和 kzalloc 时,请考虑以下事项:

  1. 仅在不需要使用 slab 缓存时使用 kmalloc 和 kzalloc。
  2. 始终使用 kzalloc 代替 kmalloc,除非您需要分配的内存不初始化为 0。
  3. 确保释放所有由 kmalloc 或 kzalloc 分配的内存。内存泄漏可能会导致系统不稳定。

使用 kfree 时,请考虑以下事项:

  1. 仅使用 kfree 释放由 kmalloc 或 kzalloc 分配的内存。释放非 slab 分配的内存可能会导致内核崩溃。
  2. 确保在释放之前无效化内存中的指针。这将有助于防止释放后使用悬空指针。
  3. 始终遵循内核文档中概述的最佳实践。
  4. 使用诸如 Valgrind 之类的工具来检测内存泄漏和使用错误。
  5. 定期审核代码以查找潜在的内存管理问题。
  6. 考虑使用 GFP_NOWAIT 标志来避免在内存分配失败时内核挂起。
  7. 考虑使用 GFP_DMA 标志来分配可用于 DMA 的内存。
  8. 考虑使用 vmalloc() 函数来分配大块连续内存。
6.最佳实践

使用 slab、kmalloc、kzalloc 和 kfree 的最佳实践以避免问题:

  1. 始终使用 kzalloc 代替 kmalloc,除非您需要分配的内存不初始化为 0。这将有助于防止使用未初始化的内存,从而导致未定义的行为。
  2. 释放所有由 kmalloc 或 kzalloc 分配的内存。内存泄漏可能会导致系统不稳定,甚至内核崩溃。
  3. 仅使用 kfree 释放由 kmalloc 或 kzalloc 分配的内存。释放非 slab 分配的内存可能会导致内核崩溃。
  4. 在释放之前无效化内存中的指针。这将有助于防止释放后使用悬空指针。
  5. 使用 slab 缓存来分配和释放内核对象。 slab 缓存旨在提高内核对象内存分配和释放的效率和可扩展性。
  6. 仅在不需要使用 slab 缓存时使用 kmalloc 和 kzalloc。这将有助于减少内存碎片。
  7. 监视 slab 缓存的使用情况,以检测内存泄漏或碎片。可以通过使用诸如 /proc/slabinfo 之类的工具来实现这一点。
  8. 使用诸如 Valgrind 之类的工具来检测内存泄漏和使用错误。这可以帮助您在问题导致系统不稳定之前识别并修复它们

避免问题的其他技巧:

  1. 考虑使用 GFP_NOWAIT 标志来避免在内存分配失败时内核挂起。这对于实时应用程序或对延迟敏感的代码非常有用。
  2. 考虑使用 GFP_DMA 标志来分配可用于 DMA 的内存。这对于需要直接内存访问的设备驱动程序非常有用。
  3. 考虑使用 vmalloc() 函数来分配大块连续内存。这对于分配超过单个页面大小的内存非常有用。
7.总结


通过学习上面教程,遵循这些最佳实践,您可以安全有效地使用 slab、kmalloc、kzalloc 和 kfree 来管理内核内存,并避免常见的内存管理问题。

这篇关于14 内核开发-slab 子系统,kmalloc、kzalloc 和 kfree的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/944412

相关文章

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

基于Python开发一个有趣的工作时长计算器

《基于Python开发一个有趣的工作时长计算器》随着远程办公和弹性工作制的兴起,个人及团队对于工作时长的准确统计需求日益增长,本文将使用Python和PyQt5打造一个工作时长计算器,感兴趣的小伙伴可... 目录概述功能介绍界面展示php软件使用步骤说明代码详解1.窗口初始化与布局2.工作时长计算核心逻辑3

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1

如何基于Python开发一个微信自动化工具

《如何基于Python开发一个微信自动化工具》在当今数字化办公场景中,自动化工具已成为提升工作效率的利器,本文将深入剖析一个基于Python的微信自动化工具开发全过程,有需要的小伙伴可以了解下... 目录概述功能全景1. 核心功能模块2. 特色功能效果展示1. 主界面概览2. 定时任务配置3. 操作日志演示

JavaScript实战:智能密码生成器开发指南

本文通过JavaScript实战开发智能密码生成器,详解如何运用crypto.getRandomValues实现加密级随机密码生成,包含多字符组合、安全强度可视化、易混淆字符排除等企业级功能。学习密码强度检测算法与信息熵计算原理,获取可直接嵌入项目的完整代码,提升Web应用的安全开发能力 目录

一文教你如何解决Python开发总是import出错的问题

《一文教你如何解决Python开发总是import出错的问题》经常朋友碰到Python开发的过程中import包报错的问题,所以本文将和大家介绍一下可编辑安装(EditableInstall)模式,可... 目录摘要1. 可编辑安装(Editable Install)模式到底在解决什么问题?2. 原理3.

Python+PyQt5开发一个Windows电脑启动项管理神器

《Python+PyQt5开发一个Windows电脑启动项管理神器》:本文主要介绍如何使用PyQt5开发一款颜值与功能并存的Windows启动项管理工具,不仅能查看/删除现有启动项,还能智能添加新... 目录开篇:为什么我们需要启动项管理工具功能全景图核心技术解析1. Windows注册表操作2. 启动文件

使用Python开发Markdown兼容公式格式转换工具

《使用Python开发Markdown兼容公式格式转换工具》在技术写作中我们经常遇到公式格式问题,例如MathML无法显示,LaTeX格式错乱等,所以本文我们将使用Python开发Markdown兼容... 目录一、工具背景二、环境配置(Windows 10/11)1. 创建conda环境2. 获取XSLT