RT-Thread学习笔记(14):内存管理

内存管理的基本概念

在计算系统中,变量、中间数据一般存放在系统存储空间中,只有在实际使用时才将它们从存储空间调入到中央处理器内部进行运算。通常存储空间可以分为两种:内部存储空间和外部存储空间。
在这里插入图片描述
RT-Thread操作系统将内核与内存管理分开实现,操作系统内核仅规定了必要的内存管理函数原型,而不关心这些内存管理函数是如何实现的,所以在RT-Thread中提供了多种内存分配算法(分配策略),但是上层接口(API)却是统一的。这样做可以增加系统的灵活性:用户可以选择对自己更有利的内存管理策略,在不同的应用场合使用不同的内存分配策略。

在嵌入式程序设计中内存分配应该是根据所设计系统的特点来决定选择使用动态内存分配还是静态内存分配算法,一些可靠性要求非常高的系统应选择使用静态的,而普通的业务系统可以使用动态来提高内存使用效率。静态可以保证设备的可靠性但是需要考虑内存上限,内存使用效率低,而动态则是相反
在这里插入图片描述
RT-Thread的内存管理模块管理系统的内存资源,它是操作系统的核心模块之一。主要包括内存的初始化分配以及释放
在这里插入图片描述
在一般的实时嵌入式系统中,由于实时性的要求,很少使用虚拟内存机制。所有的内存都需要用户参与分配直接操作物理内存,所分配的内存不能超过系统的物理内存,所有的系统堆栈的管理,都由用户自己管理。

同时,在嵌入式实时操作系统中,对内存的分配时间要求更为苛刻,分配内存的时间必须是确定的。一般内存管理算法是根据需要存储的数据的长度在内存中去寻找一个与这段数据相适应的空闲内存块,然后将数据存储在里面。而寻找这样一个空闲内存块所耗费的时间是不确定的,因此对于实时系统来说,这就是不可接受的,实时系统必须要保证内存块的分配过程在可预测的确定时间内完成,否则实时线程对外部事件的响应也将变得不可确定。

而在嵌入式系统中,内存是十分有限而且是十分珍贵的,用一块内存就少了一块内存,而在分配中随着内存不断被分配和释放,整个系统内存区域会产生越来越多的碎片,因为在使用过程中,申请了一些内存,其中一些释放了,导致内存空间中存在一些小的内存块,它们地址不连续,不能够作为一整块的大内存分配出去,所以一定会在某个时间,系统已经无法分配到合适的内存了,导致系统瘫痪。其实系统中实际是还有内存的,但是因为小块的内存的地址不连续,导致无法分配成功,所以我们需要一个优良的内存分配算法来避免这种情况的出现

不同的嵌入式系统具有不同的内存配置时间要求。所以单一的内存分配算法只可能适合部分应用程序。因此,RT-Thread将内存分配作为可移植层面(相对于基本的内核代码部分而言),RT-Thread有针对性的提供了不同的内存分配管理算法,这使得应用于不同场景的设备可以选择适合自身内存算法。

RT-Thread的内存管理模块的算法总体上可分为两类:静态内存管理动态内存管理,而动态内存管理又根据可用内存的多少划分为两种情况:一种是针对小内存块的分配管理(小内存管理算法),另一种是针对大内存块的分配管理(SLAB管理算法),需要使用的时候开启其对应的宏定义即可。
在这里插入图片描述
RT-Thread的内存管理模块通过对内存的申请、释放操作,来管理用户和系统对内存的使用,使内存的利用率和使用效率达到最优,同时最大限度地解决系统的内存碎片问题。

RT-Thread的内存管理分为静态内存管理和动态内存管理,提供内存初始化、分配、释放等功能但是各有优缺点。
在这里插入图片描述

内存管理的运作机制

动态分配内存与静态分配内存的区别:静态内存一旦创建就指定了内存块的大小,分配只能以内存块大小粒度进行分配;动态内存分配则根据运行时环境确定需要的内存块大小,按照需要分配内存

静态分配内存适合于可以确定需要占用内存多少的情况,静态分配内存的效率比动态分配内存的效率,但静态内存的利用率却比动态内存,因为只能按照已经定义的内存块粒度大小进行分配,而动态内存则可以按需分配。

静态内存管理

内存池(Memory Pool)是一种用于分配大量大小相同小内存对象的技术。它可以极大加快内存分配/释放的速度。

内存池在创建时先向系统申请一大块内存,然后分成大小相等的多个小内存块,小内存块直接通过链表连接起来(此链表也称为空闲内存链表)。每次分配的时候,从空闲内存链表中取出表头上第一个内存块,提供给申请者。物理内存中允许存在多个大小不同的内存池,每一个内存池又由多个大小相同的空闲内存块组成。当一个内存池对象被创建时,内存池对象就被分配给了一个内存池控制块,内存控制块的参数包括内存池名,内存缓冲区,内存块大小,块数以及一个等待线程列表。

内核负责给内存池分配内存池对象控制块,它同时也接收用户线程的分配内存块申请,当获得申请信息后,内核就可以从内存池中为线程分配内存块。内存池一旦初始化完成,内部的内存块大小将不能再做调整。
在这里插入图片描述

动态内存管理

动态内存管理是一个真实的堆(Heap)内存管理模块。动态内存管理,即在内存资源充足的情况下,从系统配置的一块比较大的连续内存,根据用户需求,在这块内存中分配任意大小的内存块。当用户不需要该内存块时,又可以释放回系统供下一次使用。

小堆内存管理模块主要针对系统资源比较少,一般用于小于2M内存空间的系统;而SLAB内存管理模块则主要是在系统资源比较丰富时,提供了一种近似多内存池管理算法的快速算法。两种内存管理模块在系统运行时只能选择其中之一或者完全不使用动态堆内存管理器,这两种内存管理模块提供的API接口完全相同

小内存管理模块

小内存管理算法是一个简单的内存分配算法。初始时,它是一块大的内存,其大小为(MEM_SIZE),当需要分配内存块时,将从这个大的内存块上分割出相匹配的内存块,然后把分割出来的空闲内存块还回给堆管理系统中。每个内存块都包含一个管理用的数据头,通过这个头把使用块与空闲块用双向链表的方式链接起来(内存块链表)
在这里插入图片描述
在这里插入图片描述
每个内存块(不管是已分配的内存块还是空闲的内存块)都包含一个数据头,其中包括:

  • magic – 变数(或称为幻数),它会被初始化成0x1ea0(即英文单词heap),用于标记这个内存块是一个内存管理用的内存数据块;
  • used - 指示出当前内存块是否已经分配。

magic变数不仅仅用于标识这个数据块是一个内存管理用的内存数据块,实质也是一个内存保护字:如果这个区域被改写,那么也就意味着这块内存块被非法改写(正常情况下只有内存管理器才会去碰这块内存)。

在这里插入图片描述
空闲链表指针lfree初始指向32字节的内存块。当用户线程要再分配一个64字节的内存块时,但此lfree指针指向的内存块只有32字节并不能满足要求,内存管理器会继续寻找下一内存块,当找到再下一块内存块,128字节时,它满足分配的要求。因为这个内存块比较大,分配器将把此内存块进行拆分,余下的内存块(52字节)继续留在lfree链表中。
在这里插入图片描述
每次分配内存块前,都会留出12字节数据头用于magic,used信息及链表节点使用。返回给应用的地址实际上是这块内存块12字节以后的地址,而数据头部分是用户永远不应该改变的部分。

SLAB内存管理模块

RT-Thread的SLAB分配器实现主要是去掉了其中的对象构造及析构过程,只保留了纯粹的缓冲型的内存池算法。SLAB分配器会根据对象的类型(主要是大小)分成多个区(zone),也可以看成每类对象有一个内存池。
在这里插入图片描述
在这里插入图片描述

一个zone的大小在32k ~ 128k字节之间,分配器会在堆初始化时根据堆的大小自动调整。系统中最多包括72种对象的zone,最大能够分配16k的内存空间,如果超出了16k那么直接从页分配器中分配。每个zone上分配的内存块大小是固定的,能够分配相同大小内存块的zone会链接在一个链表中,而72种对象的zone链表则放在一个数组(zone array)中统一管理。

下面是动态内存分配器主要的两种操作:

  • 内存分配: 假设分配一个32字节的内存,SLAB内存分配器会先按照32字节的值,从zone array链表表头数组中找到相应的zone链表。如果这个链表是空的,则向页分配器分配一个新的zone,然后从zone中返回第一个空闲内存块。如果链表非空,则这个zone链表中的第一个zone节点必然有空闲块存在(否则它就不应该放在这个链表中),那么就取相应的空闲块。如果分配完成后,zone中所有空闲内存块都使用完毕,那么分配器需要把这个zone节点从链表中删除。
  • 内存释放:分配器需要找到内存块所在的zone节点,然后把内存块链接到zone的空闲内存块链表中。如果此时zone的空闲链表指示出zone的所有内存块都已经释放,即zone是完全空闲的,那么当zone链表中全空闲zone达到一定数目后,系统就会把这个全空闲的zone释放到页面分配器中去。

内存管理的应用场景

RT-Threadd操作系统将内核与内存管理分开实现操作系统内核仅规定了必要的内存管理函数原型,而不关心这些内存管理函数是如何实现的。这样做大有好处,可以增加系统的灵活性:不同的应用场合可以使用不同的内存分配实现,用户也能自己通过API接口进行对内存的管理,选择对自己更有利的内存管理策略。

内存管理的主要工作是动态划分并管理用户分配好的内存区间,主要是在用户需要使用大小不等的内存块的场景中使用,当用户需要分配内存时,可以通过操作系统的动态内存申请函数索取指定大小内存块,一旦使用完毕,通过动态内存释放函数归还所占用内存,使之可以重复使用
静态内存管理是当用户需要使用固定长度的内存时,可以使用静态内存分配的方式获取内存,一旦使用完毕,通过静态内存释放函数归还所占用内存,使之可以重复使用。

例如我们需要定义一个float型数组:float Arr[];

但是,在使用数组的时候,总有一个问题困扰着我们:数组应该有多大?在很多的情况下,你并不能确定要使用多大的数组,可能为了避免发生错误你就需要把数组定义得足够大。即使你知道想利用的空间大小,但是如果因为某种特殊原因空间利用的大小有增加或者减少,你又必须重新去修改程序,扩大数组的存储范围。这种分配固定大小的内存分配方法称之为静态内存分配。这种内存分配的方法存在比较严重的缺陷,在大多数情况下会浪费大量的内存空间,在少数情况下,当你定义的数组不够大时,可能引起下标越界错误,甚至导致严重后果。

我们用动态内存分配就可以解决上面的问题。所谓动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

静态内存管理接口

静态内存的典型场景开发流程:

  • 规划一片内存区域作为静态内存池。
  • 调用rt_mp_create()函数。进行静态内存使用前的创建。
  • 调用rt_mp_alloc()函数。系统内部将会从空闲链表中获取第一个空闲块,并返回该块的用户空间地址。
  • 调用rt_mp_free()函数。将该块内存加入空闲块链表,进行内存的释放。

动态内存管理接口

动态内存的典型场景开发流程:

  • 初始化系统堆内存空间:rt_system_heap_init()。
  • 申请任意大小的动态内存:rt_malloc()。
  • 释放动态内存rt_free()。回收系统内存,供下一次使用。

附:memheap 管理算法

memheap 管理算法适用于系统含有多个地址可不连续的内存堆。使用 memheap 内存管理可以简化系统存在多个内存堆时的使用:当系统中存在多个内存堆的时候,用户只需要在系统初始化时将多个所需的 memheap 初始化,并开启 memheap 功能就可以很方便地把多个 memheap(地址可不连续)粘合起来用于系统的 heap 分配。
在这里插入图片描述

本节笔记参考于:野火-《RT-Thread内核实现与应用开发实战》
RT-Thread官方文档:内存管理

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RT-Thread的menuconfig是一个用于配置RT-Thread内核和组件的工具。通过menuconfig,用户可以方便地选择和配置所需的功能和驱动。menuconfig的配置结果会保存在rtconfig.h文件中,而不是直接修改该文件。这样做的好处是,在重新运行menuconfig时,之前的配置不会被覆盖。rtconfig.h文件中的宏可以作为功能和文件的编译开关,用于控制代码的编译。例如,可以使用config JSFW_USING_HWS_CMD bool "HWS : Enable hws test cmd" default n来定义一个名为JSFW_USING_HWS_CMD的宏,并设置其默认值为n。这样,在编译时可以根据该宏的值来决定是否启用相应的功能。\[1\]\[3\] #### 引用[.reference_title] - *1* *3* [RT-Thread 入门学习笔记 - menuconfig Kconfig的使用](https://blog.csdn.net/tcjy1000/article/details/111567253)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [RT-thread 添加 Env 环境 和添加menuconfig功能,修改文件结构](https://blog.csdn.net/qq50031185/article/details/112310748)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值