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开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

如何安装HWE内核? Ubuntu安装hwe内核解决硬件太新的问题

《如何安装HWE内核?Ubuntu安装hwe内核解决硬件太新的问题》今天的主角就是hwe内核(hardwareenablementkernel),一般安装的Ubuntu都是初始内核,不能很好地支... 对于追求系统稳定性,又想充分利用最新硬件特性的 Ubuntu 用户来说,HWEXBQgUbdlna(Har

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

C#图表开发之Chart详解

《C#图表开发之Chart详解》C#中的Chart控件用于开发图表功能,具有Series和ChartArea两个重要属性,Series属性是SeriesCollection类型,包含多个Series对... 目录OverviChina编程ewSeries类总结OverviewC#中,开发图表功能的控件是Char

鸿蒙开发搭建flutter适配的开发环境

《鸿蒙开发搭建flutter适配的开发环境》文章详细介绍了在Windows系统上如何创建和运行鸿蒙Flutter项目,包括使用flutterdoctor检测环境、创建项目、编译HAP包以及在真机上运... 目录环境搭建创建运行项目打包项目总结环境搭建1.安装 DevEco Studio NEXT IDE

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类