Linux内核内存分配函数kmalloc、kzalloc和vmalloc

这篇具有很好参考价值的文章主要介绍了Linux内核内存分配函数kmalloc、kzalloc和vmalloc。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在内核环境中,常用的内存分配函数主要有kmalloc、kzalloc和vmalloc这三个。既然这三函数都能在内核申请空间,那么这三个函数有什么区别呢?如何选用呢?

kmalloc

首先是kmalloc,其函数原型为

// /include/linux/slab.h
void *kmalloc(size_t size, gfp_t flags)

函数的特点:
申请的内存虚拟地址和物理地址都是连续的,允许申请的内存大小较小,具体的数值限制由平台和配置决定,具体可见kmalloc允许申请的内存大小。

常用的内存分配方法flags:

  • GFP_ATOMIC --表明分配内存的过程是原子的,不会被高优先级的进程或者中断打断
  • GFP_KERNEL – 常规分配
  • GFP_DMA – 给DMA分配内存时使用,使用该标志时分配的虚拟地址和物理地址都是连续的

常见的flags组合

  • 普通进程中,分配内存时可以睡眠: GFP_KERNEL
  • 普通进程中,分配内存时不可以睡眠: GFP_ATOMIC
  • 中断处理程序,tasklet:GFP_ATOMIC
  • DMA,可以睡眠:GFP_DMA | GFP_KERNEL
  • DMA,不可以睡眠:GFP_DMA | GFP_ATOMIC

kzalloc

与kmalloc基本一致,就是kmalloc的特例,是后者的封装,在flags与上了__GFP_ZERO这个标志,表示在分配完内存后对分配的内存进行清零,所以使用起来比较方便。

// /include/linux/slab.h
static inline __alloc_size(1) void *kzalloc(size_t size, gfp_t flags)
{
	return kmalloc(size, flags | __GFP_ZERO);
}

kzalloc和kmalloc所对应的内存释放函数都是kfree

void kfree(const void *objp);

vmalloc

函数原型

// /include/linux/vmalloc.h
void *vmalloc(unsigned long size);

vmalloc申请的内存的虚拟地址是连续的,但其对应的物理地址不是连续的,因此其申请的内存大小没有限制,因此申请较大的内存时可以使用这个函数。vmalloc申请内存的过程中可以睡眠,因此不能用于中断上下文中。

对应的内存释放函数为

void vfree(const void *addr);

一般来说,为了性能,通常使用kzalloc/kmalloc分配内存,如果要分配的内存过大则使用vmalloc

示例程序

//mem_alloc.c
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

static int __init mem_alloc_init(void);
static void __exit mem_alloc_exit(void);

#define KMALLOC_SIZE 131072
#define KZALLOC_SIZE 131072
#define VMALLOC_SIZE 4194304 //4096 * 1024 bytes

char* kmalloc_pt = NULL;
char* kmalloc_pt_large = NULL;
char* kzalloc_pt = NULL;
char* vmalloc_pt = NULL;

int __init mem_alloc_init(void)
{
    printk("####### Enter Module #######\n");
    kmalloc_pt = (char*) kmalloc(KMALLOC_SIZE, GFP_KERNEL);
    if (kmalloc_pt == NULL)
    {
        return -1;
    }
    else 
    {
        printk("kmalloc 128 KB memory successfully!, addr=0x%lx\n", (unsigned long)kmalloc_pt);
    }
    //用kmalloc分配4096kb内存,会失败
    kmalloc_pt_large = (char*) kmalloc(VMALLOC_SIZE, GFP_KERNEL);
    if (kmalloc_pt_large == NULL)
    {
        printk("kmalloc 4096 KB memory failed.\n");
    }
    else 
    {
        printk("kmalloc 4096 KB memory successfully!, addr=0x%lx\n", (unsigned long)kmalloc_pt_large);
    }
    kzalloc_pt = (char*) kzalloc(KZALLOC_SIZE, GFP_KERNEL);
    if (kzalloc_pt == NULL)
    {
        return -1;
    }
    else 
    {
        printk("kzalloc 128 KB memory successfully!, addr=0x%lx\n", (unsigned long)kzalloc_pt);
    }
    //用vmalloc分配4096kb内存,成功
    vmalloc_pt = (char*) vmalloc(VMALLOC_SIZE);
    if (vmalloc_pt == NULL)
    {
        return -1;
    }
    else 
    {
        printk("vmalloc 4096 KB memory successfully!, addr=0x%lx\n", (unsigned long)vmalloc_pt);
    }
    printk("#####################\n");
    return 0;
}

void __exit mem_alloc_exit(void)
{
    printk("####### Exit Module #######\n");
    if (kmalloc_pt)
    {
        kfree(kmalloc_pt);
        printk("kfree kmalloc_pt\n");
        kmalloc_pt = NULL;
    }
    if (kmalloc_pt_large)
    {
        kfree(kmalloc_pt_large);
        printk("kfree kmalloc_pt_large\n");
        kmalloc_pt_large = NULL;
    }
    if (kzalloc_pt)
    {
        kfree(kzalloc_pt);
        printk("kfree kzalloc_pt\n");
        kzalloc_pt = NULL;
    }
    if (vmalloc_pt)
    {
        vfree(vmalloc_pt);
        printk("vfree vmalloc_pt\n");
        vmalloc_pt = NULL;
    }
    printk("exit module.\n");
    printk("#####################\n");
}

module_init(mem_alloc_init);
module_exit(mem_alloc_exit);

编译完后使用insmod命令加载模块,不使用该模块时使用rmmod命令卸载模块
kzalloc,C\C++\Linux,linux,服务器,c语言,开源
使用dmesg命令查看模块加载和卸载的输出
kzalloc,C\C++\Linux,linux,服务器,c语言,开源
kzalloc,C\C++\Linux,linux,服务器,c语言,开源
从输出中可以看到,在我的电脑上kmallockzalloc可以成功分配128kb内存,但在分配更大的4096kb内存时则失败了,而vmalloc则可以成功分配4096kb的内存。

关于kmalloc/kzalloc具体最大可以分配多大的内存由平台和配置决定,不是一个固定的值,想要弄清楚需要阅读源码。

由上,在内核编程时,申请较小内存时应该优先使用kmalloc/kzalloc,在申请较大内存时使用vmalloc

参考

https://www.coolcou.com/linux-kernel/linux-kernel-memory-management-api/the-linux-kernel-kzalloc.html
https://blog.csdn.net/lu_embedded/article/details/51588902

https://blog.csdn.net/lunhui2016/article/details/114297346文章来源地址https://www.toymoban.com/news/detail-595587.html

到了这里,关于Linux内核内存分配函数kmalloc、kzalloc和vmalloc的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux内核模块vmalloc和kmalloc系统调用的代码实战

    当设备长时间运行后,内存碎片化,很难找到连续的物理页。在这种情况下,如果需要分配长度超过一页的内存块,可以使用不连续页分配器,分配虚拟地址连续但是物理地址不连续的内存块。在 32 位系统中不连分配器还有一个好处:优先从高端内存区域分配页,保留稀缺的

    2023年04月16日
    浏览(36)
  • Linux 内核内存管理 virt_to_page 函数

    virt_to_page宏根据内核虚拟地址返回其struct page 结构体指针。 x86_64: virt_to_page(kaddr) 宏通过__pa宏将虚拟地址转换为物理地址,然后右移PAGE_SHIFT(12位)位将物理地址转换为页帧号pfn,最后调用pfn_to_page将页帧号pfn转换为struct page 结构体指针,实现了将虚拟地址转换为对应struc

    2024年02月12日
    浏览(34)
  • C语言 malloc动态内存分配函数

    malloc函数:malloc时动态内存分配函数,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,就是当数组创建长度不一定 害怕数据存储不够或者不能浪费时间 在使用malloc开辟空间时,使用完成一定要释放空间,如果不释放会造内存泄漏。n在使用ma

    2024年02月07日
    浏览(43)
  • 从 malloc 分配大块内存失败 来简看 linux 内存管理

    应用进程 malloc 返回了null,但是观察到的os 的free内存还有较大的余量 ,很奇怪为什么会这样? 不可能是oom导致的(当然也没有 os 的oom 日志),free还有余量,系统也没有cgroup的应用隔离。 我们linux上使用的库函数 malloc 基本都是用glibc库实现的malloc函数(当然如果binary 链接

    2024年02月08日
    浏览(50)
  • 【Linux内核】内存管理——内存回收机制

    转载请注明: https://www.cnblogs.com/Ethan-Code/p/16626560.html 前文提到malloc的内存分配方式,malloc申请的是虚拟内存,只有在程序去访问时,才会触发缺页异常进入内核态,在缺页中断函数中建立物理内存映射。 如果物理内存充足,则直接建立页框与页的映射。当物理内存不足时,内

    2023年04月09日
    浏览(49)
  • Linux 内核学习 3 - 虚拟内存和物理内存

    虚拟内存其实是 CPU 和操作系统使用的一个障眼法,联手给进程编织了一个假象,让进程误以为自己独占了全部的内存空间 : 在 32 位系统中,进程以为自己独占了 3G 的内存空间。 在 64 位系统中,进程以为自己独占了 128T 的内存空间。 这么做的好处是,操作系统为每个进程

    2024年01月21日
    浏览(46)
  • 深入理解Linux内核--内存寻址

    使用80x86微处理器时,需区分三种不同地址。 1.逻辑地址,每一个逻辑地址都由一个段和偏移量组成。 2.线性地址(虚拟地址),如果是32位系统,则位一个32位无符号整数。可表达高达4GB地址。 3.物理地址,用于内存芯片级内存单元寻址。与从微处理器的地址引脚发到内存总

    2024年02月13日
    浏览(41)
  • 深入理解Linux内核——内存管理(1)

    提要:本系列文章主要参考 MIT 6.828课程 以及两本书籍 《深入理解Linux内核》 《深入Linux内核架构》 对Linux内核内容进行总结。 内存管理的实现覆盖了多个领域: 内存中的物理内存页的管理 分配大块内存的伙伴系统 分配较小内存的slab、slub、slob分配器 分配非连续内存块的

    2024年02月13日
    浏览(46)
  • 深入理解Linux内核——内存管理(2)

    提要:本系列文章主要参考 MIT 6.828课程 以及两本书籍 《深入理解Linux内核》 《深入Linux内核架构》 对Linux内核内容进行总结。 内存管理的实现覆盖了多个领域: 内存中的物理内存页的管理 分配大块内存的伙伴系统 分配较小内存的slab、slub、slob分配器 分配非连续内存块的

    2024年02月13日
    浏览(40)
  • 深入理解Linux内核——内存管理(3)

    提要:本系列文章主要参考 MIT 6.828课程 以及两本书籍 《深入理解Linux内核》 《深入Linux内核架构》 对Linux内核内容进行总结。 内存管理的实现覆盖了多个领域: 内存中的物理内存页的管理 分配大块内存的伙伴系统 分配较小内存的slab、slub、slob分配器 分配非连续内存块的

    2024年02月13日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包