例子:存储日志,最多存128条,每条最大1MB。

内存方面 因为嵌入式不适合用动态内存,会产生碎片。这里我们用 u8 data[LOG_SIZE];开辟固定128MB的内存区,再对其分为128个1MB内存块进行管理。

管理方法为:使用一个内存控制块结构体MCB,再编写增删改函数操作MCB进行管理。

队列方面我们使用循环队列,比如队列最多10个元素,我们存第11个元素时就会覆盖第一个。

管理方法为:使用一个队列控制块结构体LoopQueue,再编写增删改函数操作LoopQueue进行管理。

内存块与队列的关联是靠指针:

比如(存了信息的内存块1)与(队列位置1)

①我们可以把内存块1的地址指针存入队列位置1;

②也可以再定义个新结构体,包含内存块1的地址指针、信息的序号、信息的时间。再将这个结构体的指针存入队列位置1。

一、管理128MB内存

#define LOG_SIZE 0x8000000  //  (0x8000000 / 1024 / 1024= 128)
#define Blk_Num 128 //内存控制块结构体 Memory control block
typedef struct _MCB {
void* BeginAddr; //指向开辟的内存的首地址
uint32 TotalSize; //开辟内存的总大小
uint32 BlkSize; //每个内存块的大小
uint32 BlkNums; //开辟的总内存块数目
uint32 FreeBlks; //可用的内存块数目
uint32 BlkOut; //获取内存时释放的位置
uint32 BlkIn; //回收内存时存放的位置
uint32 MemAddr[Blk_Num];//该数组存储所有内存块的首地址
} MCB; //对指定内存的实际操作就靠这两个全局变量
u8 data[LOG_SIZE];
MCB LogMCB; //初始化,应该用函数执行,这里简单贴出来:
memset(data,0,sizeof(u8)*LOG_SIZE); LogMCB.BeginAddr = data;
LogMCB.TotalSize = 0x8000000*sizeof(u8); //128MB
LogMCB.BlkSize = 0x100000*sizeof(u8); //1MB
LogMCB.BlkNums = LogMCB.TotalSize/LogMCB.BlkSize;
LogMCB.FreeBlks = LogMCB.BlkNums;
LogMCB.BlkIn = 0;
LogMCB.BlkOut = 0;
For(i=0;i<LogMCB.BlkNums;i++)
{
LogMCB.MemAddr[i] = LogMCB.BeginAddr+(i*LogMCB.BlkSize);
} //获取一块内存时各变量对应的操作:
LogMCB.MemAddr[LogMemObj.BlkOut] = 0; 置零
LogMCB.BeginAddr; 不变
LogMCB.TotalSize; 不变
LogMCB.BlkSize; 不变
LogMCB.BlkNums; 不变
LogMCB.FreeBlks--; 减一
LogMCB.BlkOut++; 加一
LogMCB.BlkIn; 不变 //释放一块内存时各变量对应的操作:
LogMCB.MemAddr[LogMemObj.BlkIn] = addr; 赋值
LogMCB.BeginAddr; 不变
LogMCB.TotalSize; 不变
LogMCB.BlkSize; 不变
LogMCB.BlkNums; 不变
LogMCB.FreeBlks++; 加一
LogMCB.BlkOut; 不变
LogMCB.BlkIn++; 加一

代码为功能解析,实际使用应将初始化内存、获取内存、释放内存包装为函数。



//要理解内存控制结构体 每个成员的意义及用法

typedef struct _MCB {

void* BeginAddr; //指向开辟的内存的首地址

uint32 TotalSize; //开辟内存的总大小

uint32 BlkSize; //每个内存块的大小

uint32 BlkNums; //开辟的总内存块数目

uint32 FreeBlks; //可用的内存块数目

uint32 BlkOut; //获取内存时释放的位置

uint32 BlkIn; //回收内存时存放的位置

uint32 MemAddr[Blk_Num];//该数组存储所有内存块的首地址

} MCB;

//对指定内存的实际操作就靠这两个全局变量

u8 data[LOG_SIZE];

MCB LogMCB;

二、用循环队列管理日志

假如我们对日志是一直进行收发操作的,那么实际队列可能只用50条,就能满足128条日志的收发了。所以队列数不一定要内存块数这么大。

#define MAX 128
typedef struct _LoopQueue
{
uint32 QueueMax; //队列最大数目
uint32 QueueUsed; //使用了的数目
uint32 QueueIn; //进队位置
uint32 QueueOut; //出队位置
void *Member[MAX]; //存储每条日志的结构体指针
} LoopQueue; LoopQueue LogQueue; //initial
LogQueue.QueueMax = MAX;
LogQueue.QueueUsed = 0;
LogQueue.QueueIn = 0;
LogQueue.QueueOut = 0;
for(int i=0;i<MAX;i++)
{
LogQueue.Member[i] = NULL;
} //存储一条日志到内存块后,将内存块地址存入队列。我们发送日志时 直接操作队列、间接操作内存块:
void *nowlog = LogMCB.MemAddr[LogMemObj.BlkOut] ;
LogMCB.MemAddr[LogMCB.FreeRingOut] = 0;
LogMCB.FreeBlks--;
LogMCB.BlkOut++; LogQueue.Member[LogQueue.QueueIn] = (void *)nowlog ;
LogQueue.QueueUsed ++;
LogQueue.QueueIn ++; //删除一条日志时:
LOG * nlog = (LOG *)LogQueue.Member[LogQueue.QueueOut] ;
LogQueue.Member[LogQueue.QueueOut] = NULL;
LogQueue.QueueOut ++;
LogQueue.QueueUsed --; LogMCB.MemAddr[LogMCB.BlkIn] = (void *)nlog;
LogMCB.FreeBlks++;
LogMCB.BlkIn++; //队列实现循环:
LogQueue.QueueIn = LogQueue.QueueIn % LogQueue.QueueMax ; //比如存第129条,会存储到物理第一条的位置
LogQueue.QueueOut = LogQueue.QueueOut % LogQueue.QueueMax ;



比较重要的就是内存初始化,内存使用,内存回收,队列初始化,队列使用,队列回收。对日志实际赋值以外很多地方都是用的指针进行交互。

主要要理解存储、删除日志时:内存的管理、队列的管理方式:

//存储一条日志时:

//1、使用一个内存块

void* nowlog = LogMCB.MemAddr[LogMCB.BlkOut] ;

LogMCB.MemAddr[LogMCB.FreeRingOut] = 0;

LogMCB.FreeBlks--;

LogMCB.BlkOut++;

//2、在地址处写日志(不一定用这种方法)

memcpy(nowlog ,pdata, 0x100000*sizeof(u8));



//3、将日志指针存入队列

LogQueue.Member[LogQueue.QueueIn] = (void )nowlog ;

LogQueue.QueueUsed ++;

LogQueue.QueueIn ++;



//删除一条日志时:

//1、取出队列中的日志指针

void
nowlog = (LOG *)LogQueue.Member[LogQueue.QueueOut] ;

LogQueue.Member[LogQueue.QueueOut] = NULL;

LogQueue.QueueOut ++;

LogQueue.QueueUsed --;

//2、该日志指针也是内存块首地址指针,回收该内存块

LogMCB.MemAddr[LogMCB.BlkIn] = (void *)nlog;

LogMCB.FreeBlks++;

LogMCB.BlkIn++;

//队列实现循环:

LogQueue.QueueIn = LogQueue.QueueIn % LogQueue.QueueMax ;

//比如存第129条,会存储到物理第一条的位置

LogQueue.QueueOut = LogQueue.QueueOut % LogQueue.QueueMax ;

嵌入式无操作系统下管理内存和队列(类UCOS II思想)的更多相关文章

  1. 轻量级操作系统FreeRTOS的内存管理机制(一)

    本文由嵌入式企鹅圈原创团队成员朱衡德(Hunter_Zhu)供稿. 近几年来,FreeRTOS在嵌入式操作系统排行榜中一直位居前列,作为开源的嵌入式操作系统之一,它支持许多不同架构的处理器以及多种编译 ...

  2. glibc下的内存管理

    在解码过程中我们也遇到了类似的问题,第一次解码的音频比较大60s,耗了3G的内存,reset之后内存并没有退还给操作系统,第二次即使解一个10s的音频 几周前我曾提到,我被项目组分配去做了一些探究li ...

  3. 通俗易懂,C#如何安全、高效地玩转任何种类的内存之Span的脾气秉性(二)。 异步委托 微信小程序支付证书及SSL证书使用 SqlServer无备份下误删数据恢复 把list集合的内容写入到Xml中,通过XmlDocument方式写入Xml文件中 通过XDocument方式把List写入Xml文件

    通俗易懂,C#如何安全.高效地玩转任何种类的内存之Span的脾气秉性(二).   前言 读完上篇<通俗易懂,C#如何安全.高效地玩转任何种类的内存之Span的本质(一).>,相信大家对sp ...

  4. iOS: ARC & MRC下string内存管理策略探究

    ARC & MRC下string内存管理策略探究 前两天跟同事争论一个关于NSString执行copy操作以后是否会发生变化,两个人整了半天,最后写代码验证了一下,发现原来NSString操作 ...

  5. ARC下的内存管理

    1.ARC下单对象内存管理 局部变量释放对象随之被释放 int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = ...

  6. 嵌入式实时操作系统μCOS原理与实践任务控制与时间的解析

    /*************************************************************************************************** ...

  7. linux 操作系统下c语言编程入门

    2)Linux程序设计入门--进程介绍 3)Linux程序设计入门--文件操作 4)Linux程序设计入门--时间概念 5)Linux程序设计入门--信号处理 6)Linux程序设计入门--消息管理  ...

  8. Java是如何管理内存的?

    本文转自CSDN用户Kevin涂腾飞的文章java内存管理机制:http://blog.csdn.net/tutngfei1129287460/article/details/7383480 JAVA ...

  9. 嵌入式LINUX环境下视频采集知识

    V4L2是Linux环境下开发视频采集设备驱动程序的一套规范(API),它为驱动程序的编写提供统一的接口,并将所有的视频采集设备的驱动程序都纳入其的管理之中.V4L2不仅给驱动程序编写者带来极大的方便 ...

随机推荐

  1. JavaGuide--Java篇

    本文避免重复造轮子,也是从JavaGuider中提取出来方便日后查阅的手册 参考链接: JavaGuider:https://javaguide.cn/java/basis/java-basic-qu ...

  2. 利用Monkey进行APP测试

    APP测试策略 功能测试 安装.卸载测试 升级测试(跨版本) 数据丢失 版本兼容 业务逻辑测试 UI测试 异常测试 适配测试 软件 兼容性测试 硬件 性能测试 效率测试 启动时间 响应时间 页面流畅度 ...

  3. 02 前端基础之CSS

    目录 前端基础之CSS css简介 基本选择器(重要) 组合选择器(重点) 属性选择器 分组与嵌套 伪类选择器 伪元素选择器 选择器的优先级 字体相关 背景属性 边框属性 display属性 盒子模型 ...

  4. Python内置模块(re+collections+time等模块)

    Python内置模块(re+collections+time等模块) 1. re模块 import re 在python要想使用正则必须借助于模块 re就是其中之一 1.1 findall功能( re ...

  5. Solution -「HEOI/TJOI 2016」「洛谷 P2824」排序

    \(\mathcal{Description}\)   Link.   给定排列 \(\{p_n\}\) 和 \(m\) 次局部排序操作,求操作完成后第 \(q\) 位的值.   \(n,m\le10 ...

  6. 常用模块(Day25-Day28)

    模块分为三种: 1.内置模块:python安装时自带的. 2.扩展模块:别人写的,需要安装之后可以直接使用,如django,tornado等. 3.自定义模块:自己写的模块. 序列化模块 序列指字符串 ...

  7. python进阶(25)协程

    协程的定义 协程(Coroutine),又称微线程,纤程.(协程是一种用户态的轻量级线程) 作用:在执行 A 函数的时候,可以随时中断,去执行 B 函数,然后中断B函数,继续执行 A 函数 (可以自动 ...

  8. 图文并茂详解 NAT 协议!

    什么是 NAT 协议 我们的计算机要想访问互联网上的信息,就需要一个地址,而且这个地址是大家(其他主机)所认可的,是公共的,这个地址也叫做公有 IP 地址. 与之相对的,除了公有 IP 地址外,还有私 ...

  9. RENIX 软件如何进行IP地址管理——网络测试仪实操

    本文主要介绍了BIGTAO网络测试仪如何通过RENIX软件进行IP地址管理.文章分为五部分内容,第一部分介绍了如何通过机框显示屏查看IP地址,之后几部分分别介绍了机框按钮修改.机框接显示器/键盘修改. ...

  10. 【C#TAP 异步编程】构造函数 OOP

    原文:异步 OOP 2:构造函数 (stephencleary.com) 异步构造带来了一个有趣的问题.能够在构造函数中使用会很有用,但这意味着构造函数必须返回一个表示将来将构造的值,而不是构造的值. ...