Linux vmalloc/vfree函数实现解读

2024-04-20 20:38

本文主要是介绍Linux vmalloc/vfree函数实现解读,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

高端物理地址的分配采用vmalloc/vfree这组函数进行,什么是高端物理内存呢?我们知道Linux给内核预留了一部分虚拟地址空间,这部分虚拟地址如果能全部直接映射到物理地址空间就不存在高端内存。如果这部分内存有一部分不能直接映射到地址空间,那么这部分虚拟地址空间称为高端内存。因此,高端内存是虚拟地址空间中的概念。举个例子:如果你的物理内存为512M,那么就不存在高端内存的分配,如果你的物理地址为2G,那么有1G+128M(预留给VMALLOC区)是属于高端内存的。高端内存的分配即便是逻辑上连续,也不要求物理上是连续的。

       下面我们介绍一下高端内存的分配。分配高端内存是通过调用vmalloc函数。我们来解读一下该函数的分配过程。

首先介绍一下这部分内存管理所需要的数据结构:

struct vm_struct {

       void               *addr; // 虚拟地址的开始

       unsigned long         size; // 分配大小

       unsigned long         flags; // 标志位

       struct page            **pages; // 对应的页面

       unsigned int           nr_pages; // 页面数量

       unsigned long         phys_addr; // 物理地址

       struct vm_struct    *next; // 单链表,指向下一个vm节点

};

 

1.         首先检查请求分配的内存大小有没有超过最大的物理页面数。如果超过返回0,表示分配失败。

       size = PAGE_ALIGN(size);

       if (!size || (size >> PAGE_SHIFT) > num_physpages)

              return NULL;

2.         使用kmallocslab中,分配vm_struct数据结构。

       area = kmalloc_node(sizeof(*area), GFP_KERNEL, node);

3.         在单链表vmlist中查找适合的位置,并将新的vm节点插入到单链表中。

       for (p = &vmlist; (tmp = *p) != NULL ;p = &tmp->next) {

              if ((unsigned long)tmp->addr < addr) {

                     if((unsigned long)tmp->addr + tmp->size >= addr)

                            addr = ALIGN(tmp->size +

                                        (unsigned long)tmp->addr, align);

                     continue;

              }

              if ((size + addr) < addr)

                     goto out; // 地址越界

              if (size + addr <= (unsigned long)tmp->addr)

                     goto found; // 查找成功。进行插入操作

              addr = ALIGN(tmp->size + (unsigned long)tmp->addr, align);

              if (addr > end - size)

                     goto out; // 地址越界

       }

       // 插入新的vm节点到vmlist中去。

       area->next = *p;

       *p = area;

       // 初始化新结点

       area->flags = flags;

       area->addr = (void *)addr;

       area->size = size;

       // 物理内存还未分配。

       area->pages = NULL;

       area->nr_pages = 0;

       area->phys_addr = 0;

 

4.         接下来初始化vm_struct结构中的pagesnr_pages字段。

a)         初始化nr_pages字段

              nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;

b)        初始化pages数组

计算数组大小

       array_size = (nr_pages * sizeof(struct page *));

如果数组大小大于1个页面,在非连续区进行分配,否则在连续区进行分配

       if (array_size > PAGE_SIZE)

              pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);

       else

              pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node);

area->pages = pages;

 

5.         从伙伴系统中进行物理内存页面的分配

       for (i = 0; i < area->nr_pages; i++) {

              if (node < 0)

                     area->pages[i] = alloc_page(gfp_mask); // 针对UMA

              else

                     area->pages[i] = alloc_pages_node(node, gfp_mask, 0); // 针对NUMA

              if (unlikely(!area->pages[i])) {

                     /* Successfully allocated i pages, free them in __vunmap() */

                     area->nr_pages = i;

                     goto fail;

              }

       }

 

6.    将刚申请的页面映射到页表中。

        if (map_vm_area(area, prot, &pages))           

 

释放内存部分很简单,就是从vmlist当中删除掉对应的节点。然后将内存归还给伙伴系统。

这篇关于Linux vmalloc/vfree函数实现解读的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/921269

相关文章

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo