【linux 内存管理】预留内存、大块内存申请cblock

2023-10-17 19:30

本文主要是介绍【linux 内存管理】预留内存、大块内存申请cblock,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    内核对于有申请100M、200M大内存的连续地址时,如果基于伙伴系统分配是不太可行的,首先伙伴系统最大支持11阶即即8M的内存,即使调整最大阶数,内核在初始化伙伴系统是也不能有存在多个大阶内存,如果被分配或者裂变后再申请就有可能申请不到。所以有个方案就是将内存预留出来,比如8g预留出4g,专门用于大块内存申请,cblock就是实现的这个方案。

一、预留内存初始化

    

nr_map:预留内存块计数

addr:预留内存块的起始地址

size:内存块大小

type:内存块类型,我们常用的是BOOT_MEM_RAM

    这个全局变量是保存可以进行预留操作的物理内存起始位置和大小等信息。具体都有那些会添加到这个全局变量没有找全,以下是个人理解。首先找到一个地方就是mem初始化时候setup_arch()->arch_mem_init()->add_mem_addpart()->add_memory_region()add_memory_region()会把预留出来的大块连续的物理内存放入到这个全局变量。放在这个全局变量里的物理内存也不是全部预留,只是我们可以从这个块里来申请预留的内存。

   预留的内存大小我们是通过DTS文件解析获得。获得之后开始在boot_mem_map中选择一个可以申请的内存块申请预留的内存。

这里暂时没看懂这个reserve_start为什么这么这么计算。紧接着将已申请的预留内存通过cmemblock_add()放在全局变量cmmblock来管理

 

va_start:预留内存虚拟地址的起始地址

va_end:预留内存虚拟地址的结束地址

pfn_start:预留内存虚拟地址的起始帧号

pfn_end: 预留内存虚拟地址的结束帧号

    接下来我们所有什么的大块内存只需要通过cmmblock来管理。

    向cmmblock插入预留内存并不是只有上面的流程可以插入,比如conplat_reserve_memory()函数也是预留了内存最后放入了cmmblock。

二、大块内存申请cmmblock

大块内存申请是我们公司自己实现的一个内存管理的一个模块,自己维护内存的分配与释放,并不经过伙伴系统或者slab。

    对上文提到的所有预留内存都通过初始化函数cmm_block_init()初始化到全局单链表cblock_head中,如下:

block_start:预留内存的虚拟地址的开始地址

block_end:预留内存的虚拟地址的结束地址

free_size:预留内存大小 

下面就是内存分配:

void * __cmm_alloc_block(unsigned long size, unsigned int mid,const void *caller)
{struct cblock *block;struct cblock_area *area;void *addr = NULL;int reclaim = CMM_FREE_PAGE_RECLAIM_STATE;int nocache = 0;size = PAGE_ALIGN(size);area = cblock_area_cache_alloc();if (unlikely(!area))return NULL;if (mid)area->caller = caller;elsearea->caller = NULL;
retry:block = cblock_head;if (block->free_size >= size){addr = cblock_alloc_area(block,area,size,nocache);}if (!addr && block->next){addr = cblock_alloc_area(block->next,area,size,nocache);}    
#ifndef CONFIG_64BITif (likely(addr))atomic_long_add((long)(size >> 10), &reserved_num);                 
#endif              return addr;
}

 cblock_area_cach_alloc()函数从一个area链表中获取一个area,如果没有从slab中获取猜测释放时会放入到链表中。

 

static void *cblock_alloc_area(struct cblock *block, struct cblock_area *area, unsigned long size, int nocache)
{/*block:全局预留内存链表area:申请的内存区域记录size:申请内存大小*/struct cblock_area *first;unsigned long addr;unsigned long addr_end;unsigned long flags;/* 加硬终端锁 */spin_lock_irqsave(&block->lock,flags);/* 预留内存大于剩余内存 */if (size > block->free_size)goto overflow;if (!block->area_cache || size <= block->area_hole || nocache){block->area_hole = 0;block->area_cache = NULL;}addr_end = block->block_end;if (block->area_cache){first = block->area_cache;addr = first->area_end;}else{addr = block->block_start;if (!list_empty(&block->area_list))first = list_first_entry(&block->area_list,struct cblock_area, list);elsegoto found;}while (addr + size > first->area_start && addr + size <=  addr_end){if (addr + block->area_hole < first->area_start)block->area_hole = first->area_start - addr;addr = first->area_end;if (list_is_last(&first->list, &block->area_list)){goto found;}first = list_entry(first->list.next, struct cblock_area, list);}found:if (addr + size > addr_end)goto overflow;/* area记录所申请的内存起始和结束位置 */area->area_start = addr;area->area_end	= addr + size;/* 更新block的信息 */block->free_size -= size;block->area_cache = area;cblock_insert_area(block,area);spin_unlock_irqrestore(&block->lock,flags);return (void *)addr;overflow:spin_unlock_irqrestore(&block->lock,flags);return NULL;}

每个area记录申请的大内存信息,申请的这个area一共挂在两个表中,一个是单链表中,一个是红黑树中。

这篇关于【linux 内存管理】预留内存、大块内存申请cblock的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Linux磁盘分区、格式化和挂载方式

《Linux磁盘分区、格式化和挂载方式》本文详细介绍了Linux系统中磁盘分区、格式化和挂载的基本操作步骤和命令,包括MBR和GPT分区表的区别、fdisk和gdisk命令的使用、常见的文件系统格式以... 目录一、磁盘分区表分类二、fdisk命令创建分区1、交互式的命令2、分区主分区3、创建扩展分区,然后

Linux中chmod权限设置方式

《Linux中chmod权限设置方式》本文介绍了Linux系统中文件和目录权限的设置方法,包括chmod、chown和chgrp命令的使用,以及权限模式和符号模式的详细说明,通过这些命令,用户可以灵活... 目录设置基本权限命令:chmod1、权限介绍2、chmod命令常见用法和示例3、文件权限详解4、ch

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

关于Java内存访问重排序的研究

《关于Java内存访问重排序的研究》文章主要介绍了重排序现象及其在多线程编程中的影响,包括内存可见性问题和Java内存模型中对重排序的规则... 目录什么是重排序重排序图解重排序实验as-if-serial语义内存访问重排序与内存可见性内存访问重排序与Java内存模型重排序示意表内存屏障内存屏障示意表Int

Linux使用nohup命令在后台运行脚本

《Linux使用nohup命令在后台运行脚本》在Linux或类Unix系统中,后台运行脚本是一项非常实用的技能,尤其适用于需要长时间运行的任务或服务,本文我们来看看如何使用nohup命令在后台... 目录nohup 命令简介基本用法输出重定向& 符号的作用后台进程的特点注意事项实际应用场景长时间运行的任务服

什么是cron? Linux系统下Cron定时任务使用指南

《什么是cron?Linux系统下Cron定时任务使用指南》在日常的Linux系统管理和维护中,定时执行任务是非常常见的需求,你可能需要每天执行备份任务、清理系统日志或运行特定的脚本,而不想每天... 在管理 linux 服务器的过程中,总有一些任务需要我们定期或重复执行。就比如备份任务,通常会选在服务器资

SpringBoot使用minio进行文件管理的流程步骤

《SpringBoot使用minio进行文件管理的流程步骤》MinIO是一个高性能的对象存储系统,兼容AmazonS3API,该软件设计用于处理非结构化数据,如图片、视频、日志文件以及备份数据等,本文... 目录一、拉取minio镜像二、创建配置文件和上传文件的目录三、启动容器四、浏览器登录 minio五、

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

Linux限制ip访问的解决方案

《Linux限制ip访问的解决方案》为了修复安全扫描中发现的漏洞,我们需要对某些服务设置访问限制,具体来说,就是要确保只有指定的内部IP地址能够访问这些服务,所以本文给大家介绍了Linux限制ip访问... 目录背景:解决方案:使用Firewalld防火墙规则验证方法深度了解防火墙逻辑应用场景与扩展背景:

IDEA中的Kafka管理神器详解

《IDEA中的Kafka管理神器详解》这款基于IDEA插件实现的Kafka管理工具,能够在本地IDE环境中直接运行,简化了设置流程,为开发者提供了更加紧密集成、高效且直观的Kafka操作体验... 目录免安装:IDEA中的Kafka管理神器!简介安装必要的插件创建 Kafka 连接第一步:创建连接第二步:选