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

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

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

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

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

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

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

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

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

一、管理128MB内存

  1. #define LOG_SIZE 0x8000000 // (0x8000000 / 1024 / 1024= 128)
  2. #define Blk_Num 128
  3. //内存控制块结构体 Memory control block
  4. typedef struct _MCB {
  5. void* BeginAddr; //指向开辟的内存的首地址
  6. uint32 TotalSize; //开辟内存的总大小
  7. uint32 BlkSize; //每个内存块的大小
  8. uint32 BlkNums; //开辟的总内存块数目
  9. uint32 FreeBlks; //可用的内存块数目
  10. uint32 BlkOut; //获取内存时释放的位置
  11. uint32 BlkIn; //回收内存时存放的位置
  12. uint32 MemAddr[Blk_Num];//该数组存储所有内存块的首地址
  13. } MCB;
  14. //对指定内存的实际操作就靠这两个全局变量
  15. u8 data[LOG_SIZE];
  16. MCB LogMCB;
  17. //初始化,应该用函数执行,这里简单贴出来:
  18. memset(data,0,sizeof(u8)*LOG_SIZE);
  19. LogMCB.BeginAddr = data;
  20. LogMCB.TotalSize = 0x8000000*sizeof(u8); //128MB
  21. LogMCB.BlkSize = 0x100000*sizeof(u8); //1MB
  22. LogMCB.BlkNums = LogMCB.TotalSize/LogMCB.BlkSize;
  23. LogMCB.FreeBlks = LogMCB.BlkNums;
  24. LogMCB.BlkIn = 0;
  25. LogMCB.BlkOut = 0;
  26. For(i=0;i<LogMCB.BlkNums;i++)
  27. {
  28. LogMCB.MemAddr[i] = LogMCB.BeginAddr+(i*LogMCB.BlkSize);
  29. }
  30. //获取一块内存时各变量对应的操作:
  31. LogMCB.MemAddr[LogMemObj.BlkOut] = 0; 置零
  32. LogMCB.BeginAddr; 不变
  33. LogMCB.TotalSize; 不变
  34. LogMCB.BlkSize; 不变
  35. LogMCB.BlkNums; 不变
  36. LogMCB.FreeBlks--; 减一
  37. LogMCB.BlkOut++; 加一
  38. LogMCB.BlkIn; 不变
  39. //释放一块内存时各变量对应的操作:
  40. LogMCB.MemAddr[LogMemObj.BlkIn] = addr; 赋值
  41. LogMCB.BeginAddr; 不变
  42. LogMCB.TotalSize; 不变
  43. LogMCB.BlkSize; 不变
  44. LogMCB.BlkNums; 不变
  45. LogMCB.FreeBlks++; 加一
  46. LogMCB.BlkOut; 不变
  47. 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条日志的收发了。所以队列数不一定要内存块数这么大。

  1. #define MAX 128
  2. typedef struct _LoopQueue
  3. {
  4. uint32 QueueMax; //队列最大数目
  5. uint32 QueueUsed; //使用了的数目
  6. uint32 QueueIn; //进队位置
  7. uint32 QueueOut; //出队位置
  8. void *Member[MAX]; //存储每条日志的结构体指针
  9. } LoopQueue;
  10. LoopQueue LogQueue;
  11. //initial
  12. LogQueue.QueueMax = MAX;
  13. LogQueue.QueueUsed = 0;
  14. LogQueue.QueueIn = 0;
  15. LogQueue.QueueOut = 0;
  16. for(int i=0;i<MAX;i++)
  17. {
  18. LogQueue.Member[i] = NULL;
  19. }
  20. //存储一条日志到内存块后,将内存块地址存入队列。我们发送日志时 直接操作队列、间接操作内存块:
  21. void *nowlog = LogMCB.MemAddr[LogMemObj.BlkOut] ;
  22. LogMCB.MemAddr[LogMCB.FreeRingOut] = 0;
  23. LogMCB.FreeBlks--;
  24. LogMCB.BlkOut++;
  25. LogQueue.Member[LogQueue.QueueIn] = (void *)nowlog ;
  26. LogQueue.QueueUsed ++;
  27. LogQueue.QueueIn ++;
  28. //删除一条日志时:
  29. LOG * nlog = (LOG *)LogQueue.Member[LogQueue.QueueOut] ;
  30. LogQueue.Member[LogQueue.QueueOut] = NULL;
  31. LogQueue.QueueOut ++;
  32. LogQueue.QueueUsed --;
  33. LogMCB.MemAddr[LogMCB.BlkIn] = (void *)nlog;
  34. LogMCB.FreeBlks++;
  35. LogMCB.BlkIn++;
  36. //队列实现循环:
  37. LogQueue.QueueIn = LogQueue.QueueIn % LogQueue.QueueMax ; //比如存第129条,会存储到物理第一条的位置
  38. 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. 手把手教你实现pynq-z2条形码识别

    我是 雪天鱼,一名FPGA爱好者,研究方向是FPGA架构探索和SOC设计. 关注公众号,拉你进"IC设计交流群". 1.前言 单单实现一个二维码识别就花了将近一个星期,这篇文章我就 ...

  2. Solution -「LOJ #138」「模板」类欧几里得算法

    \(\mathcal{Description}\)   Link.   \(T\) 组询问,每次给出 \(n,a,b,c,k_1,k_2\),求 \[\sum_{x=0}^nx^{k_1}\left\ ...

  3. 【第二十三期】春招实习阶段性总结(阿里云已OC)

    本人算是一个半路出家找工作的菜鸡了,现在手中阿里云云原生offer.百度度小满offer.腾讯PCG二面环节.美团点评等offer环节.希望我的经历分享能对各位或之后准备春招的同学有帮助. 个人背景 ...

  4. 暑假撸系统6- Thymeleaf ajax交互!

    本来用Thymeleaf也没想着深度使用ajax,就是用也是非常传统的ajax方式提交然后js控制修改下变量.闲来无事的时候看Thymeleaf的教程发现一哥们的实现方式,以及实现思路,堪称惊奇,先说 ...

  5. 请求XSS攻击原理

    起因 巨人的肩膀 一个神秘URL酿大祸,差点让我背锅! (qq.com)

  6. 解决:阿里云服务器被植入挖矿程序后修改密码失败的问题(报错:passwd: Authentication token manipulation error)

    如下图,在修改密码的时候会报错 原因: 通常不能修改密码都是/etc/passwd文件或者/etc/shadow文件被锁住了 解决: 检查/etc/passwd文件和/etc/shadow文件是否被锁 ...

  7. [源码解析] NVIDIA HugeCTR,GPU 版本参数服务器---(7) ---Distributed Hash之前向传播

    [源码解析] NVIDIA HugeCTR,GPU 版本参数服务器---(7) ---Distributed Hash之前向传播 目录 [源码解析] NVIDIA HugeCTR,GPU 版本参数服务 ...

  8. 如何深入学习Java并发编程?

    在讲解深入学习Java并发编程的方法之前,先分析如下若干错误的观点和学习方法. 错误观点1:学习Java编程主要是学习多线程. 这话其实是说明了表面现象,多线程其实还真是并发编程的实现方式,但在实际高 ...

  9. 完爆Excel!一个令人惊艳的数据展示工具,让你做图更轻松高效

    数据展示应该是最常见的需求,我们经常利用数据做总结.用数据做分享.但是我们该如何更好地展示给我们需要展示的人,如何才能让我们的数据表达更加动人,这个值得让人思索. 说到数据表达,常用的数据展示方式无非 ...

  10. svn问题总结

    有问题先尝试右键刷新,或clean up svn图标不显示 解决办法:打开注册表regedit,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Curren ...