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

相关文章

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Python中help()和dir()函数的使用

《Python中help()和dir()函数的使用》我们经常需要查看某个对象(如模块、类、函数等)的属性和方法,Python提供了两个内置函数help()和dir(),它们可以帮助我们快速了解代... 目录1. 引言2. help() 函数2.1 作用2.2 使用方法2.3 示例(1) 查看内置函数的帮助(

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删