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

相关文章

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

基于Java开发一个极简版敏感词检测工具

《基于Java开发一个极简版敏感词检测工具》这篇文章主要为大家详细介绍了如何基于Java开发一个极简版敏感词检测工具,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录你是否还在为敏感词检测头疼一、极简版Java敏感词检测工具的3大核心优势1.1 优势1:DFA算法驱动,效率提升10

Python开发简易网络服务器的示例详解(新手入门)

《Python开发简易网络服务器的示例详解(新手入门)》网络服务器是互联网基础设施的核心组件,它本质上是一个持续运行的程序,负责监听特定端口,本文将使用Python开发一个简单的网络服务器,感兴趣的小... 目录网络服务器基础概念python内置服务器模块1. HTTP服务器模块2. Socket服务器模块

Java 与 LibreOffice 集成开发指南(环境搭建及代码示例)

《Java与LibreOffice集成开发指南(环境搭建及代码示例)》本文介绍Java与LibreOffice的集成方法,涵盖环境配置、API调用、文档转换、UNO桥接及REST接口等技术,提供... 目录1. 引言2. 环境搭建2.1 安装 LibreOffice2.2 配置 Java 开发环境2.3 配

Python38个游戏开发库整理汇总

《Python38个游戏开发库整理汇总》文章介绍了多种Python游戏开发库,涵盖2D/3D游戏开发、多人游戏框架及视觉小说引擎,适合不同需求的开发者入门,强调跨平台支持与易用性,并鼓励读者交流反馈以... 目录PyGameCocos2dPySoyPyOgrepygletPanda3DBlenderFife

使用Python开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3

Django开发时如何避免频繁发送短信验证码(python图文代码)

《Django开发时如何避免频繁发送短信验证码(python图文代码)》Django开发时,为防止频繁发送验证码,后端需用Redis限制请求频率,结合管道技术提升效率,通过生产者消费者模式解耦业务逻辑... 目录避免频繁发送 验证码1. www.chinasem.cn避免频繁发送 验证码逻辑分析2. 避免频繁