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

相关文章

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

python3 gunicorn配置文件的用法解读

《python3gunicorn配置文件的用法解读》:本文主要介绍python3gunicorn配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录python3 gunicorn配置文件配置文件服务启动、重启、关闭启动重启关闭总结python3 gun

kali linux 无法登录root的问题及解决方法

《kalilinux无法登录root的问题及解决方法》:本文主要介绍kalilinux无法登录root的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录kali linux 无法登录root1、问题描述1.1、本地登录root1.2、ssh远程登录root2、

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

关于pandas的read_csv方法使用解读

《关于pandas的read_csv方法使用解读》:本文主要介绍关于pandas的read_csv方法使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录pandas的read_csv方法解读read_csv中的参数基本参数通用解析参数空值处理相关参数时间处理相关

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

OpenCV图像形态学的实现

《OpenCV图像形态学的实现》本文主要介绍了OpenCV图像形态学的实现,包括腐蚀、膨胀、开运算、闭运算、梯度运算、顶帽运算和黑帽运算,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起... 目录一、图像形态学简介二、腐蚀(Erosion)1. 原理2. OpenCV 实现三、膨胀China编程(

通过Spring层面进行事务回滚的实现

《通过Spring层面进行事务回滚的实现》本文主要介绍了通过Spring层面进行事务回滚的实现,包括声明式事务和编程式事务,具有一定的参考价值,感兴趣的可以了解一下... 目录声明式事务回滚:1. 基础注解配置2. 指定回滚异常类型3. ​不回滚特殊场景编程式事务回滚:1. ​使用 TransactionT

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI