RTT学习笔记之内存管理(动态内存)
来源:互联网 发布:识别文字的软件 编辑:程序博客网 时间:2024/04/28 11:30
RTT学习笔记之内存管理(动态内存)
动态内存管理是一个真实的堆内存管理模块,可以根据用户的需求(在当前资源满足的情况下)分配任意大小的内存块。 RT-Thread系统中为了满足不同的需求,提供了两套动态内存管理算法,分别是小堆内存管理和SLAB内存管理。下堆内存管理模块主要针对系统资源比较少,一般小于2M内存空间的系统;而SLAB内存管理模块则主要是在系统资源比较丰富时,提供了一种近似的内存池管理算法。两种内存管理模块在系统运行时只能选择其中之一(或者完全不使用动态堆内存管理器),两种动态内存管理模块API形式完全相同。
一、小内存管理模块
小内存管理算法是一个简单的内存分配算法,当有可用内存的时候,会从中分割出一块来作为分配的内存,而余下的则返回到动态内存堆中。如下图所示:
当用户线程要分配一个64字节的内存块时,空闲链表指针lfree初始指向0x0001EC00内存块,但此内存块只有32字节并不能满足要求,它会继续寻找下一内存块,此内存块大小为128字节满足分配的要求。分配器将把此内存块进行拆分,余下的内存块( 52字节)继续留在lfree链表中。如下图所示:
在分配的内存块前约12字节会存放内存分配器管理用的私有数据,用户线程不应访问修改它,这个头的大小会根据配置的对齐字节数稍微有些差别。释放时则是相反的过程,但分配器会查看前后相邻的内存块是否空闲,如果空闲则合并成一个大的空闲内存块。
二、SLAB内存管理模块
RT-Thread 实现的SLAB分配器是在Matthew Dillon在DragonFly BSD中实现的SLAB分配器基础上针对嵌入式系统优化过的内存分配算法。原始的SLAB算法是Jeff Bonwick为 Solaris 操作系统首次引入的一种高效内核内存分配算法。RT-Thread的SLAB分配器实现主要是去掉了其中的对象构造及析构过程,只保留了纯粹的缓冲型的内存池算法。 SLAB分配器会根据对象的类型(主要是大小)分成多个区( zone),也可以看成每类对象有一个内存池,如图所示:
一个zone的大小在32k ~ 128k字节之间,分配器会在堆初始化时根据堆的大小自动调整。系统中最多包括72种对象的zone,最大能够分配16k的内存空间,如果超出了16k那么直接从页分配器中分配。每个zone上分配的内存块大小是固定的,能够分配相同大小内存块的zone会链接在一个链表中,而72种对象的zone链表则放在一个数组( zone arry)中统一管理。
动态内存分配器主要的两种操作:
- 内存分配:假设分配一个32字节的内存,SLAB内存分配器会先按照32字节的值,从zone array链表表头数组中找到相应的zone链表。如果这个链表是空的,则向页分配器分配一个新的zone,然后从zone中返回第一个空闲内存块。如果链表非空,则这个zone链表 中的第一个zone节点必然有空闲块存在(否则它就不应该放在这个链表中),然后取相应的空闲块。如果分配完成后,导致一个zone中所有空闲内存块都使用完毕,那么分配器需要把这个zone节点从链表中删除。
- 内存释放:分配器需要找到内存块所在的zone节点,然后把内存块链接到zone的空闲内存块链表中。如果此时zone的空闲链表指示出zone的所有内存块都已经释放,即zone是完全空闲的zone。当中zone链表中,全空闲zone达到一定数目后,会把这个全空闲的zone释放到页面分配器中去。
三、动态内存接口
// 动态内存控制块:#define HEAP_MAGIC 0x1ea0struct heap_mem{ /* magic and used flag */ rt_uint16_t magic;// 如果此内存块被分配了,则置0x1ea0 rt_uint16_t used; // 0:未分配,1:已分配 rt_size_t next, prev;// 前一内存块,后一内存块};// 相关接口:void rt_system_heap_init(void *begin_addr, void *end_addr);// 初始化系统堆空间void *rt_malloc(rt_size_t size);// 分配内存块void *rt_realloc(void *rmem, rt_size_t newsize);// 重新分配内存块void *rt_calloc(rt_size_t count, rt_size_t size);// 分配多内存块void rt_free(void *rmem);// 释放内存块
四、简单示例
#include <rtthread.h>#include "finsh.h"struct rt_thread thread1;char thread1_stack[512];void thread1_entry(void* parameter){ int i; // 申请一个字符型指针数组用于存放申请到的内存地址 char *ptr[20]; // 初始化指针数组为空 memset(ptr, 0, sizeof(char*)*20); while(1) { for (i = 0; i < 20; i++) { // 每次分配(1 << i)大小字节数的内存空间 ptr[i] = rt_malloc(1 << i); if (ptr[i] != RT_NULL) { rt_kprintf("get memory: 0x%x\n", ptr[i]); // 申请成功后释放已申请到的内存块 rt_free(ptr[i]); // 将指针赋值为空 ptr[i] = RT_NULL; } } }}int rt_mem_set_init(){ rt_thread_init(&thread1, "thread1", thread1_entry, RT_NULL, &thread1_stack[0], sizeof(thread1_stack), 20, 10); rt_thread_startup(&thread1); return 0;}FINSH_FUNCTION_EXPORT(rt_mem_set_init, a Memory test example);
五、示例说明及运行结果
首先在startup.c文件中会运行rt_system_heap_init(__segment_end("HEAP"), (void*)STM32_SRAM_END);来进行堆的初始化,计算出可用内存数量并初始化堆头控制块和堆尾控制块,通过 rt_malloc(1 << i);来申请内存放到ptr的指针数组中,申请时会对传入的申请大小进行对齐并判断,最小申请内存大小为12字节,用来存放内存分配器管理用的私有数据。通过不断查找链表来找到满足要求的空闲内存,找到后将内存地址返回,没有则返回空。
申请成功后打印所申请到的内存地址,然后进行内存释放,释放时操作类似,释放过程中需要判断前一块和后裔块内存是否为空闲,如果为空闲则进行合并操作。
0 0
- RTT学习笔记之内存管理(动态内存)
- RTT学习笔记之内存池管理(静态内存池)
- 学习笔记之内存管理
- JVM学习笔记(一)之内存管理
- JVM学习笔记(二)之内存管理
- JVM学习笔记(三)之内存管理
- winCE6.0 学习笔记之内存管理
- PowerPC体系结构学习笔记之内存管理
- unix c 学习笔记之内存管理
- ios学习笔记(三)之内存管理
- OBject-C 学习笔记之内存管理
- 学习笔记Cocos2d-x之内存管理
- 【学习笔记】嵌入式Linux之内存管理
- RTT学习笔记之内核对象模型
- OC之内存管理(笔记)
- 内存管理之内存分配
- Boost之内存管理学习(一)
- Boost之内存管理学习(二)
- Linux下用 select 函数实现定时器(也可用作线程内延时)
- android sdk离线安装
- Android双击返回键退出程序的实现方法
- Sublime Text 2支持GB2312和GBK,解决中文显示乱码问题
- codereview启发
- RTT学习笔记之内存管理(动态内存)
- oracle connect by用法
- 1.2. 初窥输入/输出
- iOS第三方开源库的吐槽和备忘
- 【待续,啊啊啊啊】【找了一遍,最后成功!!】stm32 USART 防止发送缓冲区被新来的数据覆盖
- Linux下用C语言检查指定程序名的运行实例个数
- 关于httpservice和webservice
- C++细节7
- 移动开发:dequeueReusableCellWithIdentifier的运行机制