RT-thread内核之小内存管理算法
一、动态内存管理
动态内存管理是一个真实的堆(Heap)内存管理模块,可以在当前资源满足的情况下,根据用户的需求分配任意大小的内存块。而当用户不需要再使用这些内存块时,又可以释放回堆中供其他应用分配使用。RT-Thread系统为了满足不同的需求,提供了两套不同的动态内存管理算法,分别是小内存管理算法和SLAB内存管理算法。小堆内存管理模块主要针对系统资源比较少,一般用于小于2M内存空间的系统;而SLAB内存管理模块则主要是在系统资源比较丰富时,提供了一种近似多内存池管理算法的快速算法。
两种内存管理模块在系统运行时只能选择其中之一或者完全不使用动态堆内存管理器。这两种管理模块提供的API接口完全相同。因为动态内存管理器要满足多线程情况下的安全分配,会考虑多线程间的互斥问题,所以请不要在中断服务例程中分配或释放动态内存块。因为它可能会引起当前上下文被挂起等待。
二、小内存管理算法
本文主要介绍小内存管理算法,至于SLAB内存管理算法则在后续文章中介绍。小内存管理算法是一个简单的内存分配算法。初始时,它是一块大的内存。当需要分配内存块时,将从这个大的内存块上分割出相匹配的内存块,然后把分割出来的空闲内存块还回给堆管理系统中。每个内存块都包含一个管理用的数据头,通过这个头把使用块与空闲块用双向链表的方式链接起来,如 内存块链表图所示:
内存管理的在表现主要体现在内存的分配与释放上,小型内存管理算法可以用以下例子体现出来。
空闲链表指针lfree初始指向32字节的内存块。当用户线程要再分配一个64字节的内存块时,但此lfree指针指向的内存块只有32字节并不能满足要求,内存管理器会继续寻找下一内存块,当找到再下一块内存块,128字节时,它满足分配的要求。因为这个内存块比较大,分配器将把此内存块进行拆分,余下的内存块(52字节)继续留在lfree链表中。另外,在每次分配内存块前,都会留出12字节数据头用于magic,used信息及链表节点使用。返回给应用的地址实际上是这块内存块12字节以后的地址,前面的12字节数据头是用户永远不应该碰的部分。(注:12字节数据头长度会与系统对齐差异而有所不同)。释放时则是相反的过程,但分配器会查看前后相邻的内存块是否空闲,如果空闲则合并成一个大的空闲内存块。
数据结构:在src/mem.c中
#define HEAP_MAGIC 0x1ea0
struct heap_mem
{
/* magic and used flag */
rt_uint16_t magic; //如果此内存块被分配了,则(在rt_malloc中设置)置0x1ea0。标志该内存块为一个内存管理系统使用的动态内存数据块,类似于一个内存保护字:如果这个区域被改写,那么也就意味着这块内存块被非法改写 (正常情况下只有内存管理系统才会访问它)
rt_uint16_t used; //0:未分配;1:已分配 rt_size_t next, prev; //后一内存块首地址(包含内存块控制结构),前一内存块首地址(包含内存块控制结构)。注意这里不再是rt_list_t类型(链表类型),它们直接赋值为内存地址
};
三、小内存管理算法函数接口:在src/mem.c中
初始化动态内存堆:
void rt_system_heap_init(void *begin_addr, void *end_addr);
在使用堆内存RT_USING_HEAP时,必须要在系统初始化的时候进行堆内存的初始化。这个函数会把参数begin_addr,end_addr区域的内存空间作为内存堆来使用。
由源代码可知,初始化时小内存管理算法通过传进来的起始地址和末尾地址将动态堆内存初始化为两个内存块:第一个内存块指向动态堆内存首地址,可用空间为整个可分配的内存(不包含两个内存控制块本身所占大小,即减去24字节),此内存块下一指针指向末尾内存控制块;第二个内存块指向最末尾的一个内存控制块,可用空间大小为0,此内存块前一指针和后一指针都指向本身。 分配内存块:
void *rt_malloc(rt_size_t size);
rt_malloc函数会从系统堆空间中找到合适大小的内存块,然后把内存块可用地址返回给用户。 重分配内存块:
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);
用户线程使用完从内存分配器中申请的内存后,必须及时释放,否则会造成内存泄漏,rt_free函数会把待释放的内存换回给堆管理器中。在调用这个函数时用户需传递待释放的内存块指针,如果是空指针直接返回。
内存合并:
static void plug_holes(struct heap_mem *mem);
此函数在重分配内存时调用,将分割出来的后一部分尝试与前后内存块合并;当释放内存时,算法将检查待释放内存的前一内存块和后一内存块,如果为空闲则合并。
四、算法总结
小内存管理算法从整体上来讲,是将一片内存初始化为静态链表来实现的,初始化时只有两个内存块:
第一块除了包含内存块控制块(占用12字节)外,还包含待分配的空间,这个空间就是mem_size_aligned,它是指此算法可用来作分配的动态堆内存总大小,任何待分配的内存都不能比它还大,否则超过极限;
第二块只包含内存控制块本身(占用12字节),不包含待分配的空间,它作为链表尾,且设置使用标志used为1(永久使用)。
整个算法中还有一空闲指针lfree,始终指向动态内存堆中剩余可用空间的第一个空闲内存块,初始化时指向动态内存堆起始地址,该指针变量在分配内存和合并内存时会不断更新。接下来就是分配内存了,分配内存时首先从空闲内存所指向的节点开始扫描,一旦扫描到大小满足的节点,则返回此节点,若此节点所指向的空间足够大,大到还有足够空间分配另一内存块(只含内存块控制结构)时,则分割此节点指向的内存为两块,前一块内存可用空间user data首地址返回,后一块内存设置为未分配(空闲内存); 当释放内存时,算法将检查待释放内存的前一内存块和后一内存块,如果为空闲则合并。
RT-thread内核之小内存管理算法的更多相关文章
- 源码解读·RT-Thread小内存管理算法分析
这篇文章最初发布在RT-Thread官方论坛中,最近准备整理放到博客中来让更多人一起探讨学习. 2012年9月28日星期五 前言: 母语能力有限 概述: 这篇文字和大家分享一下今晚对RT-Thread ...
- Linux内核内存管理算法Buddy和Slab: /proc/meminfo、/proc/buddyinfo、/proc/slabinfo
slabtop cat /proc/slabinfo # name <active_objs> <num_objs> <objsize> <objpersla ...
- rt-thread中动态内存分配之小内存管理模块方法的一点理解
@2019-01-18 [小记] rt-thread中动态内存分配之小内存管理模块方法的一点理解 > 内存初始化后的布局示意 lfree指向内存空闲区首地址 /** * @ingroup Sys ...
- 自动内存管理算法 —— 标记和复制法
最近阅读了<垃圾回收算法手册>这本经典的书籍,借此机会打算写几篇内存管理算法方面的文章,也算是自己的总结吧. ...
- <Linux内核源码>内存管理模型
题外语:本人对linux内核的了解尚浅,如果有差池欢迎指正,也欢迎提问交流! 首先要理解一下每一个进程是如何维护自己独立的寻址空间的,我的电脑里呢是8G内存空间.了解过的朋友应该都知道这是虚拟内存技术 ...
- 【原创】xenomai内核解析--实时内存管理--xnheap
目录 一. xenomai内存池管理 1.xnheap 2. xnpagemap 3. xnbucket 4. xnheap初始化 5. 内存块分配 5.1 小内存分配流程(<= 2*PAGE_ ...
- Linux内核剖析 之 内存管理
1. 内存管理区 为什么分成不同的内存管理区? ISA总线的DMA处理器有严格的限制:仅仅能对物理内存前16M寻址. 内核线性地址空间仅仅有1G,CPU不能直接訪问全部的物理内存. ZONE_DMA ...
- linux内核--用户态内存管理
在上一篇博客“内核内存管理”中,描述的内核内存管理的相关算法和数据结构,在这里简单描述用户态内存管理的数据结构和算法. 一,相关结构体 与进程地址空间相关的全部信息都包含在一个叫做“内存描述符”的数据 ...
- Windows内核中的内存管理
内存管理的要点 内核内存是在虚拟地址空间的高2GB位置,且由所有进程所共享,进程进行切换时改变的只是进程的用户分区的内存 驱动程序就像一个特殊的DLL,这个DLL被加载到内核的地址空间中,Driver ...
随机推荐
- 安装cuda9.0+cudnn v7+python3.5.3+tensorflow
本机设备 windows10 gtx1060 安装软件及下载地址 python-3.5.3-amd64 链接:https://pan.baidu.com/s/1I3oIDatMgvDLEtaPtvu ...
- Lucene第二讲——索引与搜索
一.Feild域 1.Field域的属性 是否分词:Tokenized 是:对该field存储的内容进行分词,分词的目的,就是为了索引. 否:不需要对field存储的内容进行分词,不分词,不代表不索引 ...
- WPF Prism MVVM 中 弹出新窗体. 放入用户控件
原文:WPF Prism MVVM 中 弹出新窗体. 放入用户控件 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qq_37214567/artic ...
- 佛山Uber优步司机奖励政策(1月11日~1月17日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- HDU 4418 Time travel
Time travel http://acm.hdu.edu.cn/showproblem.php?pid=4418 分析: 因为走到最后在折返,可以将区间复制一份,就变成了只往右走,01234321 ...
- 用wireshark查看 tcpdump 抓取的mysql交互数据
用tcpdump 抓取 mysql客户端与服务器端的交互 1开启tcpdump tcpdump -i eth0 -s 3000 port 3306 -w ~/sql.pcap 先故意输入一个错误的密 ...
- Django学习总结-之-URLS反向解析
2018-09-15 09:58:49 在CSDN博客审核效率提高之前, 又要在此处向各位唠叨了~ URL 与 URI URL : 统一资源定位符 相当于绝对路径 URI : 统一资源标志符 相当于 ...
- Skype for Business Server 方案
方案说明: 高可用性的配置屏蔽了单点故障,使得当一个服务器节点失效时,另外的可用的节点能够进行服务的接管.可伸缩性的配置可以保证当即时沟通平台的使用用户增加时,该平台应该具有良好的可伸缩性,能非常方便 ...
- 阿里云服务器 操作实战 部署C语言开发环境(vim配置,gcc) 部署J2EE网站(jdk,tomcat)
. 作者 :万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/18964835 . 博客总结 : 设置SecureCRT ...
- a2
Alpha 冲刺报告 队名: 组长:吴晓晖 今天完成了哪些任务: 代码量300+,完成了百度地图API的引入. 展示GitHub当日代码/文档签入记录: 明日计划: 整理下这两个功能,然后补些bug ...