本文主要是介绍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 时,请考虑以下事项:
- 确保为要分配的内核对象类型创建了 slab 缓存。
- 仅使用 slab 缓存分配和释放内核对象。
- 避免为非内核对象分配 slab 缓存。
- 监视 slab 缓存的使用情况,以检测内存泄漏或碎片。
使用 kmalloc 和 kzalloc 时,请考虑以下事项:
- 仅在不需要使用 slab 缓存时使用 kmalloc 和 kzalloc。
- 始终使用 kzalloc 代替 kmalloc,除非您需要分配的内存不初始化为 0。
- 确保释放所有由 kmalloc 或 kzalloc 分配的内存。内存泄漏可能会导致系统不稳定。
使用 kfree 时,请考虑以下事项:
- 仅使用 kfree 释放由 kmalloc 或 kzalloc 分配的内存。释放非 slab 分配的内存可能会导致内核崩溃。
- 确保在释放之前无效化内存中的指针。这将有助于防止释放后使用悬空指针。
- 始终遵循内核文档中概述的最佳实践。
- 使用诸如 Valgrind 之类的工具来检测内存泄漏和使用错误。
- 定期审核代码以查找潜在的内存管理问题。
- 考虑使用 GFP_NOWAIT 标志来避免在内存分配失败时内核挂起。
- 考虑使用 GFP_DMA 标志来分配可用于 DMA 的内存。
- 考虑使用 vmalloc() 函数来分配大块连续内存。
6.最佳实践
使用 slab、kmalloc、kzalloc 和 kfree 的最佳实践以避免问题:
- 始终使用 kzalloc 代替 kmalloc,除非您需要分配的内存不初始化为 0。这将有助于防止使用未初始化的内存,从而导致未定义的行为。
- 释放所有由 kmalloc 或 kzalloc 分配的内存。内存泄漏可能会导致系统不稳定,甚至内核崩溃。
- 仅使用 kfree 释放由 kmalloc 或 kzalloc 分配的内存。释放非 slab 分配的内存可能会导致内核崩溃。
- 在释放之前无效化内存中的指针。这将有助于防止释放后使用悬空指针。
- 使用 slab 缓存来分配和释放内核对象。 slab 缓存旨在提高内核对象内存分配和释放的效率和可扩展性。
- 仅在不需要使用 slab 缓存时使用 kmalloc 和 kzalloc。这将有助于减少内存碎片。
- 监视 slab 缓存的使用情况,以检测内存泄漏或碎片。可以通过使用诸如 /proc/slabinfo 之类的工具来实现这一点。
- 使用诸如 Valgrind 之类的工具来检测内存泄漏和使用错误。这可以帮助您在问题导致系统不稳定之前识别并修复它们
避免问题的其他技巧:
- 考虑使用 GFP_NOWAIT 标志来避免在内存分配失败时内核挂起。这对于实时应用程序或对延迟敏感的代码非常有用。
- 考虑使用 GFP_DMA 标志来分配可用于 DMA 的内存。这对于需要直接内存访问的设备驱动程序非常有用。
- 考虑使用 vmalloc() 函数来分配大块连续内存。这对于分配超过单个页面大小的内存非常有用。
7.总结
通过学习上面教程,遵循这些最佳实践,您可以安全有效地使用 slab、kmalloc、kzalloc 和 kfree 来管理内核内存,并避免常见的内存管理问题。
这篇关于14 内核开发-slab 子系统,kmalloc、kzalloc 和 kfree的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!