RTEMS 的堆(上)

RTEMS实时操作系统精要(1)-简介 最早用于美国国防系统,早期的名称为实时导弹系统(Real Time Executive for Missile Systems),后来改名为实时军用系统(Real Time Executive for Military Systems) 1、RTEMS(多处理系统实时可执行体)是一个为嵌入式系统而设计的自由的开源实时操作系统。 在缩写词RTEMS取其现在的含义之前,初始时代表导弹系统实时可执行体,然后变成了军用系统实时可执行体。 RTEMS曾被移殖到多个以不同类型的中央处理器(CPU)为基础的计算机系统上。 阅读详情

对于实时操作系统,好的内存分配算法会使系统的稳定性增色不少。实际使用中,如果用户在代码的使用方法和系统内存管理算法相悖,会引起许多问题,甚至使系统变得不可靠。RTEMS提供了堆(Heap)、工作空间(Workspace)、内存区域(Region)和固定尺寸的内存分配算法(Partition)。RTEMS内核使用的内存从工作空间申请,而用户应用程序使用的内存从堆申请。堆与工作空间使用相同的算法管理内存,故放在一起讨论。内存区域与堆的管理算法类似,略有区别,会和固定尺寸的内存分配算法一起在后续的章节中讨论。

 

RTEMS堆使用的内存的分配策略是最先适合法。最开始,一块整块的内存被初始化成一个堆块,经过若干次分配释放后,形成大小不一的堆块(Heap Block)。分配算法从第一个堆块开始寻找,只要堆块的空间比申请的空间大,则将该块分配给用户,停止继续搜索。如果该堆块比申请的空间大到一定的程度,分配算法会将该堆块划分成两个堆块,一个堆块是刚好满足用户申请的空间返回给用户,剩下的空间成为另外一个堆块,放入堆中等待后续的操作。

 

有分配必然有回收,RTEMS堆回收算法的思路是尽可能合并邻接的空闲堆块,形成大的堆块,供分配算法使用。回收发生在每一次释放内存时,回收算法会检查释放的内存邻接的堆块,如果左右邻接的堆块都空闲,则将左右堆块从堆中取出,一起合并成一个大的堆块放入堆中;若只有一个堆块空闲,那就合并一个;若左右邻接的堆块均不空闲,算法放弃合并,只将释放的内存变为堆块放入堆中。

 

 

这种内存分配回收的算法比较简单,速度快;可以精确分配用户指定的内存,并可对邻接的空间进行合并;然而这个算法也存在着显著的缺点,经过多次分配和释放后,堆中会产生大量的小堆块,产生资源的浪费,如上图所示,虽然空间中存在着相当余量的内存,却不能作为一个整体分配出来;随着堆块的数量增多,资源的链表也变长,搜索合适的内存块的时间也变得不确定,这会对实时性造成危害。

 

通常的,如果系统对分配时间没有特别的要求,分配的尺寸上没有剧烈的波动,释放频度不是很高,使用默认的分配算法是最简洁的。另外一些特殊情况,如分配了内存就不释放,直至系统运行结束,或分配的内存全部释放完再开始下一轮分配,也是适用这种算法的。但是如果系统对分配的实时性要求高,比较频繁的分配释放,系统连续运行时间长,分配的尺寸变化大,那么最佳的选择莫过于固定尺寸的内存分配。所
以选定内存分配方法前,要弄清楚“内存指纹”,权衡利弊,按照应用量体裁衣。

 

堆算法的实现是依靠双向链表完成的,为减少不必要的管理空间,并未直接使用上节讨论到的链表(Chain_Node)。堆和堆块的定义代码如下:

 

    /*堆的定义*/
    typedef struct {
        Heap_Block  free_list;     /*自由堆块链表的头、尾指针*/
        uint32_t    page_size;     /*最小分配尺寸和对齐要求*/
        uint32_t    min_block_size;/*最小堆块的尺寸*/
        void       *begin;         /*堆的开始地址*/
        void       *end;           /*堆的结束地址*/
        Heap_Block *start;         /*第一个合法的堆块地址*/
        Heap_Block *final;         /*最后一个合法的堆块地址*/
        Heap_Statistics stats;     /*堆运行时刻的参数统计*/
    } Heap_Control;
    /*堆块的定义*/
    typedef struct Heap_Block_struct Heap_Block;
    struct Heap_Block_struct {
        uint32_t  prev_size;       /*如果前驱堆块是自由块,表示其尺寸*/
        uint32_t  size;            /*本堆块的尺寸和前驱堆块的状态*/
        Heap_Block *next;          /*指向前驱自由块*/
        Heap_Block *prev;          /*指向后继自由块*/
    };

 

 

注意堆块中的定义:size既表示本堆块的尺寸,又表示前驱堆块的状态。RTEMS规定堆块只有使用和自由两种状态。由于堆块的尺寸都做了对齐处理,size变量的最低比特位是不会被用到的。那它的最低比特位用于存储前驱堆块的状态,当最低比特位(HEAP_PREV_USED)置1时,表示前驱堆块正在使用中;清除时,表示前驱堆块处于自由状态,等待分配。next和prev指针域只有在在本堆块是自由状态时,才是有效的;被申请后作为用户数据存储区。prev_size只有当size最低比特位(HEAP_PREV_USED)清除时,才是有效的;如果size最低比特位置1了,prev_size所在的空间会作为上一个堆块的用户可访问空间,堆的管理代码应避免访问该区域,防止造成错误。这个技巧会使管理堆块所需的额外内存减少到4个字节(只用于保存size域)。

 

 

如图/ref{heapinit}所示,一个totalsize大小的内存块被初始化为一个堆后的存储结构。这个内存块被划分为两个堆块,首堆块(first block)和尾堆块(last dummy block)。尾堆块的尺寸(size1)只有8个字节,只记录它前驱堆块的状态与尺寸,没有双向链表指针域的存储空间,所以堆管理代码不能对尾堆块进行指针链的操作。首堆块的前驱是不存在的,RTEMS就标记首堆块的前驱堆块为使用状态(size的HEAP_PREV_USED比特位置1),故prev_size的值无意义。堆结构free_list中的双向链表指针(next和prev)都指向了首堆块的地址。首堆块的prev指向了free_list,next指针应该指向首堆块的后继,初始化后有两个堆块,由于尾堆块是一个“伪”堆块,所以管理代码直接将next指向free_list,整个堆块形成环形双向链表。首堆块从next的地址到尾堆块的prev_size,是可申请被使用的空间。故堆管理程序以next的地址按对齐尺寸(page_size)对齐,而不是以prev_size的地址对齐。

因为对齐,内存初始化成堆后,开始和结束的位置有可能存在小于对齐尺寸(page_size)的间隙内存,它在整个堆的工作中都不会被使用。如果对齐尺寸与开始地址和内存尺寸配合恰当,这两个间隙将不会存在。

申请内存分配成功后,堆的存储结构会发生的变化。假设从堆中申请alloc_size个字节的内存(alloc_size能被page_size整除)。如图/ref{heapalloc}所示,满足空间要求的堆块已经被分割成两个堆块,一个大小是alloc_size个字节,另一个尺寸为size0- alloc_size个字节。第二个堆块的尺寸大于堆控制块中的min_block_size,否则堆管理程序不会分割堆块,直接将堆块地址返回。用户可访问的内存从used block + 8 一直到free block + 4的位置。处在使用状态的used block只有一个size域是用于堆管理的,free block中的prev_size域已经贡献给used block作为用户可访问的存储空间了。由于used block原来是首堆块,它前面没有堆块了,所以它的prev_size只是单纯的占个位置,不做任何用途。

 

 

堆结构体最后一个变量的定义是统计堆运行时刻的一些参数。用户可以根据这些参数优化自己的设计。Heap_Statistics的定义如下:

 

    typedef struct {
      uint32_t instance;        /*当前堆的实例数*/
      uint32_t size;            /*用于堆的内存尺寸*/
      uint32_t free_size;       /*当前的自由内存尺寸*/
      uint32_t min_free_size;   /*最小自由内存尺寸*/
      uint32_t free_blocks;     /*当前自由块的数量*/
      uint32_t max_free_blocks; /*最大自由块的数量*/
      uint32_t used_blocks;     /*当前使用块的数量*/
      uint32_t max_search;      /*每次申请内存需要最大搜索的堆块数*/
      uint32_t allocs;          /*成功调用 allocs 的总次数*/
      uint32_t searches;        /*申请内存时搜索堆块的总数*/
      uint32_t frees;           /*成功调用 free 的总次数*/
      uint32_t resizes;         /*成功调用 resizes 的总次数*/
    } Heap_Statistics;

 

 

 

RTEMS (Real-Time Executive for Multiprocessor Systems) 系统详解 凭借其优化的调度器、丰富的同步原语和对多种硬件架构的支持,RTEMS 在航空航天、国防、医疗设备等领域发挥着至关重要的作用。后来,随着项目的成熟和开源化,更名为 RTEMS。然而,需要注意的是,即使使用 POSIX API,底层实现仍然是 RTEMS 的实时机制,其行为可能与通用操作系统上的 POSIX 有细微差别,开发者需要理解 RTEMS 的实时特性。与通用操作系统的单体式内核不同,RTEMS 的内核非常精简,避免了复杂的动态功能(如运行时加载模块、虚拟内存),以确保可预测性和实时性。 阅读详情

相关推荐

Ubuntu下编译RTEMS

说明由于RTEMS 的最新版本4.12的使用信息并不完善,我们决定采用更加完善稳定的RTEMS 4.11版本,配套使用4.11的RTEMS Resource Builder。Linux下RTEMS工具链的安装Linux下的RTEMS工具链包括gcc, gdb, python等,首先使用命令安装这些工具* $ sudo apt-get build-dep binutils gcc g++ gdb un

蓝蓝蓝博特的博客 1379

RTEMS 介绍

<br />为什么需要操作系统?<br /> <br />1.计算机是由CPU、内存、磁盘、显卡、声卡等许许多多设备组成的,而且这些设备的厂商众多,品种繁多,而且不同厂商生产的同种设备虽然完成同种功能,但是具体细节却存在千差万别;<br /><br /> 2.为了正确地管理和使用这些设备来实现具体的应用,这样程序员就得了解和掌握各种设备的工作原理。而且对于同种设备,由于不同的硬件厂商在实现细节上的差异使得程序员再次陷入了复杂的硬件控制的深渊。<br /> <br />3.在硬件的基础上加载一层软件来管理整

雪松's RTEMS 2万+

飞腾CPU运行RTEMS6.0

飞腾CPU运行RTEMS

lizongjun126com的博客 1342

RTEMS线程调度算法(RMS)详解

RTEMS是以线程为基本调度单位的,调度算法基于优先级的抢占式线程调度,支持256个线程优先级。当然RTEMS值hi创建同等优先级线程,相同优先级的线程采用时间片轮转调度。调度器寻找下一个最高优先级就绪线程的时间是o(1),这是实时性得到保障的一个关键机制。 为了增强对用户应用需求的可扩展性,rtems实现了基于线程的任务扩展机制,可在创建任务、上下文切换或者删除任务等系统事件发生时插入用户指定

hahachenchen789的博客 3065

RTEMS STM32F103RCT6应用

1.准备工作 安装好RTEMS工具链,ECLIPSE插件,git RTEMS4.11最新代码。 2.安装调试工具 在FEDORA中调试STM32,可以通过GDB来调试,虽然跟在WINDOWS下调试相比易用性相差较大,但是也能达到调试的目的以及实现程序下载的功能。如果用JLINK开始用JLINK的LINUX版的软件,或者OPENOCD。在此我选择的是JLINK。下载到jlink-4.98.1.

qq_30136173的博客 3125

RTEMS连载(2) RTEMS的编译

RTEMS的编译 作者 RayRTEMS版权所有,转载请注明:来源http://www.rtems.net,作者ray@rtems.net摘要   本节主要介绍RTEMS编译的步骤。交叉编译环境建立好以后,编译就很简单了,解压rtems的文件夹$tar xjvf rtems4.6.2.tar.bz2建立rtems的编译路径:$ mkdir rtems_i386 

Ray的嵌入式专栏 2465

RTEMS 的堆(下)

<br /> <br />堆的核心操作主要有初始化、申请、释放、扩展。由于工作空间(Workspace),是供内核使用的,所以相关函数使用的全部是“_”前缀。主要操作分列如下:<br /> _Heap_Initialize,将指定的内存初始化成堆; _Heap_Allocate,从指定的堆中申请指定字节数的内存; _Heap_Allocate_aligned,从指定的堆中申请指定字节的内存,并且返回的地址还按照指定的对齐要求对齐; _Heap_Free,将指定地址的内存释放到指定的堆中; _Heap_Ext

雪松's RTEMS 2185

RTEMS 操作系统

​RTEMS,全称为 ​​(多处理器系统的实时执行体),是一个开源的实时操作系统(RTOS)​,最初由美国军方资助开发,目标是满足航空航天、国防等高安全、高性能、强实时性领域中的嵌入式系统需求。随着发展,RTEMS 已成为一个通用、高度可移植、模块化、支持多处理器架构的实时操作系统,广泛用于航空航天、工业控制、医疗设备、电信和嵌入式实时系统中。选择 RTEMS 的理由说明✅ ​高实时性与确定性​适用于任务响应要求极高的系统,如飞行控制✅ ​多核与多处理器支持​原生 SMP,适合现代多核 SoC。

baidu_38316985的博客 973

RTEMS 操作系统的概念:堆与栈

在计算机领域,堆栈是一个不容忽视的概念,只要编写程序都要用到。对于很多的初学着来说,堆栈却是一个很模糊的概念。 栈~(Stack)~在数据结构中是一种线性表,特点是先进后出~(First In Last Out,FILO)。数据结构/footnote{严蔚敏版《数据结构》}中出现堆~(heap)~的地方只有 堆排序算法。程序员口中的堆栈是存储代码中数据的方式方法,栈和数据结构中的“栈”是有些联系的,但堆和数据结构中的“堆”基本上是无任何关系的。 称呼上堆栈不分家,但实际上堆和栈的区别是非常大的。栈和数

雪松's RTEMS 2700

RTEMS的BSP开发流程

RTEMS BSP 的开发流程图,一共分为 8 个步骤:建立开发环境、选择 BSP 模板、新建 BSP 目录、建立 BSP 配置文件、修改 Makefile、修改启动代码、配置 RTEMS 和编译测试和运行。第一步:建立开发环境。主要是针对 Linux 上的环境配置,将 Linux 作为宿主环境,开发板作为目标环境。 第二步:选择 BSP 模板。这一步主要是针对目标开发板,寻找合适的 BSP。RT

蓝蓝蓝博特的博客 1761

使用STM32的HAL库移植RTEMS操作系统

文章目录编译运行RTEMS操作系统下STM32F4的BSPSTEP 1: 编译rtems工具链STEP 2: 编译RTEMS源码STEP 3: 烧写测试程序"hello",并下载STEP 4:使用GDB调试第1步:先下载bin文件到flash里面第2步:运行openocd第3步:开启一个新终端,运行gdb 编译运行RTEMS操作系统下STM32F4的BSP STEP 1: 编译rtems工具链 ...

bh_binghu的专栏 1967

RTEMS 安装脚本

(嵌入式 实时操作系统 rtos rtems 开发环境 交叉工具链 shell脚本) RTEMS 安装脚本 rtems_building_v10.sh 转载请注明出处:http://blog.youkuaiyun.com/zhumaill/article/details/21478895 #!/bin/bash #rtems4.11在linuxmint-16-cinnamon-64bit上测试通过 #设置 TARGET=arm-rtemseabi4.11 PREFIX=/opt/rtems-4.11 BSP=st

天又亮了 3372

RTEMS介绍-中文

中文介绍了RTEMS,包括简介,性能,支持的处理器,系统架构,主要的几个版本合入特性,代码获取方式,系统覆盖测试,shell,任务调度策略,同步与互斥方法以及虚拟化

飞腾派上体验 RTEMS

飞腾派是由中电港萤火工场与飞腾合作推出的飞腾派,采用飞腾自主研发的高能效异构多核处理器技术,具有模块化、易上手、全开源、低成本的特点,大大降低了国产处理器的开发使用门槛,解决了国产处理器难以普及推广的问题。- RTEMS (Real-Time Executive for Multiprocessor Systems) 是一个开源实时操作系统,可以用于太空飞行、医疗、网络和各类嵌入式设备,◆支持多处理器(不同于SMP,RTEMS中多个处理器是协作关系)同时,RTEMS 也支持了大量的特性。

paofulll的博客 1200

rtems移植代码分析之sparc-leon2

rtems移植代码分析之sparc-leon2: 对rtems中针对sparc处理器、leon2兼容板卡移植代码进行分析, 主要包括三部分代码分析:cpukit/score/cpu、 c/src/lib/libcpu/sparc、c/src/lib/libbsp/sparc/leon2 希望能对喜欢rtems或者sparc的人有所帮助,共勉!

TMS320F28377D的sys/bios双核工程配置详解——从零搭建到RAM优化

本文详细解析了TMS320F28377D双核系统在sys/bios环境下的工程配置与RAM优化策略。从开发环境搭建、SYS/BIOS工程创建到双核CMD文件配置,提供了实战技巧和常见问题解决方案,帮助开发者高效实现电力电子控制系统中的双核协作与性能优化。

weixin_28292761的博客 600

RTEMS目录树

RTEMS版权所有,转载请注明来源www.rtems.net,作者ray@rtems   第 1 节: 介绍     本章介绍了RTEMS开发环境,包括         *         RTEMS的目录结构,       *         GNU Make在 RTEMS 开发环境中的用法       *         示例应用       *         RTE

andy205214的专栏 2430

从内外参推导IPM变换方程及代码实现(生成AVM环视拼接图)

最近想实现AVM拼接,看了不少博客和论文,不过比较愚钝,一直没能很好理解原理,尤其是怎么在实现时把下文中Z1和Z2消除的,所以严谨的推导了一下对应的公式,如有不对,水平有限,烦请指出~IPM变换(逆透视变换),顾名思义,即将正常透视效应消除的变换,变换结果为鸟瞰图BEV(俯视图);AVM环视拼接一般是将车身前后左右的四个鱼眼相机拼接成环视图(也是俯视),其使用的单应矩阵将四个相机转到同一个俯视坐标系。

mxdsdo09的博客 4170

构建beagleboneblack的rtems5开发环境

编译环境说明 安装工具链 下载RTEMS内核源码 编译bsp包 编译rtems-libbsd 常见错误 一些脚本 编译环境说明 时间:2018.04.28. rtems-source-builder版本哈希值:10d3aaf。rtems-src哈希值8b5a801,rtems-libbsd哈希值ef5d536。我只是在我当前的版本编译成功,如果遇到问题无法解决可以...

bh_binghu的专栏 1995

损失函数大汇总(六十一)(Signed Distance Map Loss附公式推导与代码)

摘要 本文介绍了Signed Distance Map (SDM) Loss,一种将形状先验直接融入分割任务的方法。SDM将每个像素表示为到目标边界的带符号距离(内部为负,外部为正),相比二值mask能更连续地表达形状几何信息。SDM Loss的核心思想是让网络学习这个隐式形状场,通过可微的Heaviside函数近似将SDM转换为分割结果。文中重点分析了一种product-based regression loss,它能同时关注距离数值和内外符号的正确性,对边界区域尤为敏感。SDM Loss通常与传统的分割

悦学共鸣,温柔以待,汇聚光芒,共同成长 187

Go基础:Go语言详细介绍,环境搭建,及第一个程序详解

Go语言是Google开发的开源编程语言,具有高效、简洁、并发性强等特点。文章从Go语言的诞生背景、核心特性及应用领域展开介绍,并详细说明了Windows、Linux和macOS下的环境搭建步骤,包括安装、环境变量配置及测试方法。最后通过“Hello, World!”程序解析Go语言基本语法,并演示了编译发布和跨平台编译功能。全文涵盖了Go语言从入门到实践的完整流程,适合初学者快速上手。

数据知道的博客 6799
上一篇: 唐永泰元年无际大师 《心药方》
下一篇: RTEMS 的堆(下)
coolbacon
博客等级 码龄22年 1766粉丝 139原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值