——对指南内容做了些许整理——
7内存管理
在计算系统中,通常存储空间可以分为两种:内部存储空间(RAM)和外部存储空间(ROM)。RT-Thread 操作系统在内存管理上总体上可分为两类:(动态)内存堆管理与(静态)内存池管理。
内存管理的表现主要体现在内存的分配与释放上。
7.2内存堆管理
内存堆管理用于管理一段连续的内存空间。
物理内存中允许存在多个大小不同的内存堆。
内存堆可以在当前资源满足的情况下,根据用户的需求分配任意大小的内存块。而当用户不需要再使用这些内存块时,又可以释放回堆中供其他应用分配使用。
内存堆的缺点:
- 分配效率不高,在每次分配时,都要空闲内存块查找;
- 容易产生内存碎片。
内存堆管理算法
内存堆管理根据具体内存设备划分为三种情况:
- 小内存管理算法——针对小内存块
- slab管理算法——针对大内存块
- memheap管理算法——针对多内存堆
这几类内存堆管理算法在系统运行时只能选择其中之一或者完全不使用内存堆管理器。
1小内存管理算法
主要针对系统资源比较少的情况。
初始时,它是一块大的内存。当需要分配内存块时,将从这个大的内存块上分割出相匹配的内存块,然后把分割出来的空闲内存块还回给堆管理系统中。
释放内存时,分配器会查看前后相邻的内存块是否空闲,如果空闲则合并成一个大的空闲内存块。
2slab管理算法
主要针对系统资源比较丰富时的情况。
RT-Thread 的 slab 分配器是针对嵌入式系统优化的内存分配算法,只保留了纯粹的缓冲型的内存池算法。
slab 分配器会根据对象的大小分成多个区(zone),并在堆初始化时根据堆的大小自动调整zone的大小。
每个 zone 上分配的内存块大小是固定的,能够分配相同大小内存块的 zone 会链接在一个链表中,而 72 种对象(系统中的 zone 最多包括 72 种对象)的 zone 链表则放在一个数组(zone_array[])中统一管理。
3memheap 管理算法
memheap 管理算法适用于系统含有多个地址可不连续的内存堆。
开启 memheap 功能就可以很方便地把多个 memheap(地址可不连续)粘合起来用于系统的 heap 分配。
堆(heap);栈(stack)
工作机制:首先将多块内存加入 memheap_item 链表进行粘合。当分配内存块时,会先从默认内存堆去分配内存,当分配不到时会查找memheap_item 链表,尝试从其他的内存堆上分配内存块。
应用程序不用关心当前分配的内存块位于哪个内存堆上,就像是在操作一个内存堆。
内存堆配置和初始化
在使用内存堆时,必须要在系统初始化的时候进行堆的初始化。
7.3内存池
内存池是一种内存分配方式,用于分配大量大小相同的小内存块。它可以极大地加快内存分配与释放的速度,且能尽量避免内存碎片化。
当静态内存池具有可用内存时,系统对内存块分配的时间将是恒定的。
物理内存中允许存在多个大小不同的内存池,每一个内存池又由多个空闲内 存块组成,内核用它们来进行内存管理。
RT-Thread 的内存池支持线程挂起功能。
当内存池中无空闲内存块时,申请线程会被挂起,直到内存池中有新的可用内存块,再将挂起的申请线程唤醒。
内存块分配机制
内存池在创建时先向系统申请一大块内存,然后分成同样大小的多个小内存块,小内存块直接通过链表连接起来(此链表也称为空闲链表)。每次分配的时候,从空闲链表中取出链头上第一个内存块,提供给申请者。
内核负责给内存池分配内存池控制块,它同时也接收用户线程的分配内存块申请,当获得这些信息后,内核就可以从内存池中为内存池分配内存。内存池一旦初始化完成,内部的内存块大小将不能再做调整。
一些数据需要的内存大小在编译前可以确定,可以使用内存池管理方式。
一些数据需要的内存大小需要在程序运行过程中根据实际情况确定,并不能在编译前确定,使用内存堆管理方式。
附录 STM32分块式内存管理
本节讲解未使用 RTOS的 STM32内存管理。
以下摘自STM32F4开发指南——内存管理实验,正点原子
内存管理的实现方法有很多种,最终都是要实现两个函数: malloc 和 free。malloc函数用于内存申请; free函数用于内存释放。
分块式内存管理由内存池和内存管理表两部分组成。内存池被等分为 n块,与对应的内存管理表大小相等。内存管理表的每一个项对应内存池的一块内存,内存管理表的项值代表被连续占用的内存块数。内寸分配方向从顶到底。
分配原理
当指针 p 调用 malloc 申请内存的时候,先判断 p 要分配的内存块数(m),然后从第 n 项开始,向下查找,直到找到 m 块连续的空内存块(即对应内存管理表项为 0),然后将这 m 个内存管理表项的值都设置为 m(标记被占用),最后,把最后的这个空内存块的地址返回指针 p,完成一次分配。
注:如果当内存不够的时候(找到最后也没找到连续的 m 块空闲内存),则返回 NULL 给 p,表示分配失败。
释放原理
当 p 申请的内存用完,需要释放的时候,调用 free 函数实现。 free 函数先判断 p 指向的内存地址所对应的内存块,然后找到对应的内存管理表项目,得到 p 所占用的内存块数目 m(内存管理表项目的值就是所分配内存块的数目),将这 m 个内存管理表项目的值都清零,标记释放,完成一次内存释放。
STM32分块式内存管理和rtthread内存池管理本质基本相似。