Linux内核中动态内存分配函数解析

在C语言中,动态内存分配通常用于在运行时申请内存。在内核编程中,动态内存分配与用户空间有所不同,因为内核需要更谨慎地处理内存,且不能使用用户空间的库(如glibc)。下面我们将详细分析Linux内核中动态申请内存的函数及其区别。

Linux内核中动态内存分配函数

1. kmalloc

kmalloc函数用于在内核空间申请一块连续的内存区域。它的原型如下:

void *kmalloc(size_t size, gfp_t flags);
  • 参数
    • size:要分配的内存大小(以字节为单位)。
    • flags:分配标志,用于指定分配内存的行为和内存类型(例如GFP_KERNELGFP_ATOMIC等)。
  • 返回值:成功时返回指向分配内存的指针,失败时返回NULL
  • 特点
    • 分配的内存是物理上连续的(在虚拟地址空间也是连续的)。
    • 分配的大小有限制(通常最大为4MB,但具体取决于配置和架构)。
    • 适用于需要小块连续内存的情况(如结构体、缓冲区等)。

2. kzalloc

kzallockmalloc的一个变种,它在分配内存的同时将内存初始化为0。原型如下:

void *kzalloc(size_t size, gfp_t flags);
  • 它等价于先用kmalloc分配内存,然后用memset清零。
  • 参数和返回值与kmalloc相同。

3. vmalloc

vmalloc用于分配大块连续虚拟内存(物理内存不一定连续)。原型如下:

void *vmalloc(unsigned long size);
  • 参数
    • size:要分配的内存大小(以字节为单位)。
  • 返回值:成功时返回虚拟地址连续的指针,失败时返回NULL
  • 特点
    • 分配的内存虚拟地址连续,但物理地址可能不连续。
    • 分配的内存可以很大(远大于kmalloc的限制)。
    • 访问速度可能比kmalloc慢,因为需要建立页表映射,且可能引起TLB抖动。
    • 适用于需要大块内存且不需要物理连续性的情况(如模块加载、大型缓冲区等)。

4. kcalloc

kcalloc用于分配数组内存,并将内存初始化为0。原型如下:

void *kcalloc(size_t n, size_t size, gfp_t flags);
  • 参数
    • n:数组元素个数。
    • size:每个元素的大小。
    • flags:同kmalloc
  • 返回值:成功返回指针,失败返回NULL
  • 它分配的内存大小为n * size,并初始化为0。

5. alloc_pages / __get_free_pages

这两个函数用于直接分配页面(以页为单位)。

  • alloc_pages返回struct page *,而__get_free_pages返回虚拟地址。
  • 原型:
    struct page *alloc_pages(gfp_t gfp_mask, unsigned int order);
    unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
    
  • 参数
    • gfp_mask:分配标志。
    • order:指定分配页数的对数(即分配页数为2^order)。
  • 它们分配的内存是物理连续的,适用于大块内存需求(但比vmalloc高效,因为物理连续)。

6. kmem_cache_alloc

用于从特定的内存缓存中分配对象。内核中经常需要频繁分配和释放相同大小的内存块(如结构体),使用slab分配器可以提高效率。

  • 首先需要创建一个缓存:
    struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *));
    
  • 然后从缓存中分配:
    void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
    
  • 释放对象到缓存:
    void kmem_cache_free(struct kmem_cache *cachep, void *objp);
    
  • 销毁缓存:
    void kmem_cache_destroy(struct kmem_cache *cachep);
    

区别对比

函数物理连续虚拟连续最大大小适用场景速度
kmalloc/kzalloc较小(如4MB)小内存、需要物理连续
vmalloc很大(如多个GB)大内存、不需要物理连续
kcalloc同kmalloc数组分配并初始化为0
alloc_pages较大(多页)大块物理连续内存
kmem_cache_alloc是(通常)由缓存对象决定频繁分配释放固定大小对象非常快

分配标志(gfp_t flags)常用值

  • GFP_KERNEL:常规分配,可能睡眠(阻塞),适用于进程上下文。
  • GFP_ATOMIC:原子分配,不会睡眠,适用于中断上下文或不能睡眠的地方。
  • GFP_USER:为用户空间分配内存。
  • GFP_HIGHUSER:从高端内存为用户空间分配。
  • GFP_NOIO:禁止I/O操作(在存储管理代码中使用)。
  • GFP_NOFS:禁止文件系统操作(在文件系统代码中使用)。
  • GFP_DMA:分配可用于DMA的内存(物理地址在16MB以下)。
  • GFP_DMA32:分配可用于DMA的内存(物理地址在4GB以下)。

使用注意事项

  1. 上下文要求:在中断上下文、软中断、持有自旋锁等原子上下文中,不能使用可能睡眠的函数(如GFP_KERNEL),而应使用GFP_ATOMIC
  2. 内存泄漏:内核内存不会自动释放,必须显式释放,否则会导致内存泄漏。
  3. 碎片问题:频繁分配释放内存可能导致碎片,使用slab分配器可以减少碎片。
  4. 性能考量vmalloc分配的内存访问速度相对较慢,应避免在性能关键路径中使用。

释放内存的函数

  • kmalloc/kzalloc/kcalloc分配的内存用kfree释放。
  • vmalloc分配的内存用vfree释放。
  • __get_free_pages分配的内存用free_pages释放。
  • alloc_pages分配的内存用__free_pages释放。
  • kmem_cache_alloc分配的内存用kmem_cache_free释放。

示例代码片段

// 使用kmalloc
void *ptr = kmalloc(100, GFP_KERNEL);
if (ptr) {// 使用内存kfree(ptr);
}
// 使用vmalloc
void *vptr = vmalloc(1000000);
if (vptr) {// 使用内存vfree(vptr);
}
// 使用内存缓存
struct kmem_cache *my_cache = kmem_cache_create("my_cache", sizeof(struct my_struct), 0, 0, NULL);
struct my_struct *obj = kmem_cache_alloc(my_cache, GFP_KERNEL);
if (obj) {// 使用对象kmem_cache_free(my_cache, obj);
}
kmem_cache_destroy(my_cache);

以上是Linux内核中动态内存分配的主要函数及其区别。在实际使用中,应根据具体需求选择合适的内存分配函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/92628.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/92628.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Next.js 中配置不同页面布局方案

在 Next.js 应用中,你可以通过多种方式实现某些页面全屏、某些页面带菜单/页眉/页脚的需求。以下是几种实现方案: 方案一:使用多个布局组件 1. 创建不同的布局组件 // app/default-layout.tsx import Header from /components/header; import…

Spring Boot 使用外置 Servlet 容器:从配置到部署全指南

在 Spring Boot 开发中,我们通常使用嵌入式 Servlet 容器(如 Tomcat),它能将应用打包成可执行 JAR,简化部署流程。但在某些场景下(如需要支持 JSP、复杂的容器定制或企业级部署规范)&#xff0c…

借助AI学习开源代码git0.7之九diff-files

借助AI学习开源代码git0.7之九diff-files diff-files.c 是一个用于比较工作目录中的文件和 Git 索引(暂存区)中文件的工具。 实质上,它是 git diff命令在不指定特定提交时功能的核心实现。 主要功能分析: 1. 核心功能 diff-files …

社区资源媒体管理系统设计与实现

社区资源媒体管理系统设计与实现 1. 系统概述 社区资源媒体管理系统是一个专为社区户外广告打造的高效、专业化平台,旨在实现社区媒体的数字化管理、智能投放和便捷交易。该系统将整合社区各类广告资源,为广告主、物业公司和社区居民提供一站式服务。 1.…

12.1.6 weak_ptr

weak_ptr weak_ptr会指向一个share_ptr&#xff08;使用一个share_ptr来初始化weak_ptr&#xff09;&#xff0c;但并不会增加这个share_ptr的引用计数器&#xff0c;其析构也不会减少share_ptr的引用计数器。 构造函数及使用 #include <iostream> #include <memory&g…

深度分析Java内存模型

Java 内存模型&#xff08;Java Memory Model, JMM&#xff09;是 Java 并发编程的核心基石&#xff0c;它定义了多线程环境下线程如何与主内存&#xff08;Main Memory&#xff09;以及线程的本地内存&#xff08;工作内存&#xff0c;Working Memory&#xff09;交互的规则。…

代码随想录算法训练营第五十二天|图论part3

101. 孤岛的总面积 题目链接&#xff1a;101. 孤岛的总面积 文章讲解&#xff1a;代码随想录 思路&#xff1a; 与岛屿面积差不多&#xff0c;区别是再dfs的时候&#xff0c;如果碰到越界的&#xff0c;需要用一个符号标记这不是孤岛再continue #include <iostream> #i…

前端实现 excel 数据导出,封装方法支持一次导出多个Sheet

一、前言 后台管理项目有时会有需要前端导出excel表格的功能&#xff0c;有时还需要导出多个sheet&#xff0c;并给每个sheet重新命名&#xff0c;下面我们就来实现一下。 二、实现效果图 三、实现步骤 1、 安装 命令行安装 xlsx 和 file-saver npm install xlsx -S npm i…

【Lambda 表达式】返回值为什么是auto

一个例子&#xff1a; int x 10; auto add_x [x](int y) -> int {return x y; }; int result add_x(5); // 结果是 15lambda 是匿名类型&#xff0c;必须用 auto 来接收。&#xff08;必须写auto&#xff0c;不可省略&#xff09;内层 -> auto 是函数的返回类型自动推…

【小董谈前端】【样式】 CSS与样式库:从实现工具到设计思维的跨越

CSS与样式库&#xff1a;从实现工具到设计思维的跨越 一、CSS的本质&#xff1a;样式实现的「施工队」 CSS作为网页样式的描述语言&#xff0c;其核心能力在于&#xff1a; 精确控制元素的尺寸、位置、颜色实现响应式布局和动画效果与HTML/JavaScript协同完成交互体验 但CS…

MTSC2025参会感悟:大模型 + CV 重构全终端 UI 检测技术体系

目录 一、传统 UI 自动化的困局:高成本与低效率的双重枷锁 1.1 根深蒂固的技术痛点 1.2 多维度质量挑战的叠加 二、Page eyes 1.0:纯视觉方案破解 UI 检测困局 2.1 纯视觉检测的核心理念 2.2 页面加载完成的智能判断 2.3 视觉模型驱动的异常检测 2.4 大模型赋能未知异…

使用Claude Code从零到一打造一个现代化的GitHub Star项目管理器

在日常的开发工作中&#xff0c;我们经常会在GitHub上star一些有用的项目库。随着时间的推移&#xff0c;star的项目越来越多&#xff0c;如何有效管理这些项目成为了一个痛点。 今天&#xff0c;分享我使用Claude Code从零构建的一个GitHub Star管理插件。项目背景与需求分析 …

为什么 Linux 启动后还能升级内核?

✅ 为什么 Linux 启动后还能升级内核&#xff1f; 简单结论&#xff1a; 因为 “安装/升级内核 ≠ 当前就使用该内核”&#xff0c;Linux允许你安装多个内核版本&#xff0c;并在下次启动时选择其中一个来加载运行。 &#x1f9e0; 举个现实生活类比 你在穿一件衣服&#xff08…

Go语言实战案例-统计文件中每个字母出现频率

以下是《Go语言100个实战案例》中的 文件与IO操作篇 - 案例19&#xff1a;统计文件中每个字母出现频率 的完整内容。本案例适合用来练习文件读取、字符处理、map统计等基础技能。&#x1f3af; 案例目标读取一个本地文本文件&#xff0c;统计并打印出其中每个英文字母&#xff…

Notepad++工具操作技巧

1、notepad -> ctrlf -> 替换(正则表达式) -> $-a ->每行的行尾加a&#xff1b; 2、notepad -> ctrlf -> 替换(正则表达式) -> ^-a ->每行的行首加a &#xff1b; 3、按住alt切换为列模式 4、删除空行-不包括有空格符号的空行 查找替代 查找目标…

领码课堂 | Java与AI的“硬核“交响曲:当企业级工程思维遇上智能时代

摘要 &#x1f680; 在AI工业化落地的深水区&#xff0c;Java正以其独特的工程化优势成为中流砥柱。本文系统解构Java在AI项目全生命周期中的技术矩阵&#xff0c;通过"三阶性能优化模型"、"微服务化AI部署架构"等原创方法论&#xff0c;结合大模型部署、M…

面经 - 基于Linux的高性能在线OJ平台

真实面试环境中&#xff0c;被问到的相关问题&#xff0c;感兴趣的可以看下1. 这个项目是你独立完成的吗&#xff1f;团队中你的职责是什么&#xff1f;是的&#xff0c;这个项目是我独立完成的&#xff0c;从需求分析、系统设计到项目部署都我做的。重点工作包括&#xff1a;使…

Ubuntu 20.04 上安装 SPDK

以下是在 Ubuntu 20.04 上安装 SPDK (Storage Performance Development Kit) 的完整步骤&#xff1a;1. 系统准备# 更新系统 sudo apt update sudo apt upgrade -y# 安装基础依赖 sudo apt install -y git make gcc g libssl-dev libaio-dev libnuma-dev \pkg-config python3 p…

解决WPS图片在Excel表格中无法打开

若出现无法打开的情况&#xff0c;还请回到WPS中&#xff0c;点击图片&#xff0c;右键&#xff1a;转化为浮动图片保存&#xff0c;然后便能正常打开&#xff01;

【Ollama】open-webui部署模型

目录 一、本地部署Ollama 1.1 进入官网复安装命令 1.2 执行安装命令 1.3 验证是否安装成功 二、启动Ollama服务 三、运行模型 方法一&#xff1a;拉取模型镜像 方法二&#xff1a;拉取本地模型 四、使用Open WebUI 部署模型 4.1 创建虚拟环境 4.2 安装依赖 4.3 运行…