应用程序中为了某种特殊需要,经常需要动态的分配内存,而操作系统的特质置一,就是能不能保证动态内存分配的时效性,也就是说分配时间是可确定的

Ucos提供内存分配功能,它将内存空间分为两级管理,将一块连续的内存空间分为若干个分区,每个分区单位又分成大小相同的若干个内存块,分区时操作系统的管理单位,而内存块是分配单位,内存分区以及内存块的使用情况有一个叫做内存控制块的表来记录,内存控制块的基本结构如下

typedef struct os_mem {

void   *OSMemAddr;

void   *OSMemFreeList;

INT32U  OSMemBlkSize;

INT32U  OSMemNBlks;

INT32U  OSMemNFree;

#if OS_MEM_NAME_EN > 0u

INT8U  *OSMemName;

#endif

} OS_MEM;

OSMemAddr 内存分区的指针

OSMemFreeList 内存控制块链表的指针

OSMemBlkSize 内存块的长度

OSMemNBlks 分区内内存块的数目

OSMemNFree 分区内部当前可分配内存块数目

系统在初始化的时候将当前系统内部的所有内存控制块构成一个链表,叫做空闲内存控制块表,变量如下

OS_EXT  OS_MEM           *OSMemFreeList;

而系统初始时刻存在的内存控制块的数目是给定的

OS_EXT  OS_MEM            OSMemTbl[OS_MAX_MEM_PART];

OS_MAX_MEM_PART是一个宏,决定系统拥有几个内存分区,在os_cfg.h文件中定义

初始化内存控制块列表的函数为OS_MemInit,其中的核心code为

OS_MemClr((INT8U *)&OSMemTbl[0], sizeof(OSMemTbl));

for (i = 0u; i < (OS_MAX_MEM_PART - 1u); i++) {

pmem                = &OSMemTbl[i];

pmem->OSMemFreeList = (void *)&OSMemTbl[i + 1u];

#if OS_MEM_NAME_EN > 0u

pmem->OSMemName  = (INT8U *)(void *)"?";

#endif

}

pmem                = &OSMemTbl[i];

pmem->OSMemFreeList = (void *)0;

#if OS_MEM_NAME_EN > 0u

pmem->OSMemName = (INT8U *)(void *)"?";

#endif

OSMemFreeList   = &OSMemTbl[0];

类似于tcb初始化的流程,也是将一个数组链表化,并且将OSMemFreeList指向链表的开头,此时系统是还没有开始管理内存的,因为我们并没有告诉系统我们可分配的内存在哪里,那在哪儿指明了呢,答案是在OSMemCreate中,该函数初始化一个内存分区,并返回一个内存分区控制结构体,函数原型如下

OS_MEM  *OSMemCreate (void *addr,INT32U  nblks,INT32U  blksize,INT8U  *perr)

指明我们空闲内存分区的开始地址,我们分配的内存块的长度以及内存块的数目,三者计算就能得到我们分配的内存大小nblks*blksize

在OSMemCreate中先做了以下操作

plink = (void **)addr;

pblk  = (INT8U *)addr;

loops  = nblks - 1u;

for (i = 0u; i < loops; i++) {

pblk +=  blksize;

*plink = (void  *)pblk;

plink = (void **)pblk;

}

这句话实现的实际上是将一个内存分区分解为nblks个内存块,然后在每一个内存块的最头上位置放置了一个指针,这个指正指向下一个内存块的首地址,用图比较好解释

如上就是基本的内存管理结构了

pmem->OSMemAddr     = addr;

pmem->OSMemFreeList = addr;

pmem->OSMemNFree    = nblks;

pmem->OSMemNBlks    = nblks;

pmem->OSMemBlkSize  = blksize;

接下来就是进行了内存控制块的赋值操作,也就是说,ucos的两级内存管理实际上是通过两级链表来操作的.空闲内存控制块构成一个空闲链表,分配的内存块有内存块本身包含的指针形成单向链表,此时内存控制块的指向为可分配内存的头

而向操作系统申请内存块的函数为OSMemGet,其核心流程代码如下

if (pmem->OSMemNFree > 0u) {

pblk                = pmem->OSMemFreeList;

pmem->OSMemFreeList = *(void **)pblk;

pmem->OSMemNFree--;

该函数需要我们给出一个内存控制块指针,函数从控制块中返回空闲内存,首先检测控制块内是否还有空闲内存,若有,将最近的空闲内存返回,控制快内空闲内存-1, OSMemFreeList指向下一个空闲内存块的首地址.

而释放内存块的操作使用OSMemPut完成,该函数接受两个参数,一个是空闲内存控制块的指针,一个是想要释放的内存指针,核心代码为

*(void **)pblk      = pmem->OSMemFreeList;

pmem->OSMemFreeList = pblk;

pmem->OSMemNFree++;

通过分析以上代码可以得出,新释放的内存块被插入到空闲块的最头上地址,控制块中的空闲块指针指向释放的地址,释放地址的首地址存放原来的第一个空闲块的地址,链表恢复,并将空闲内存++;

另外可以通过OSMemQuery查询内存分区的状态,简单接口,不再赘述

但是一定要注意,ucos的内存管理是存在问题的!

在OSMemCreate中有以下语句

INT8U     *pblk;

这是一个八位指针,后面在进行内存块划分的时候有以下代码

for (i = 0u; i < loops; i++) {

pblk +=  blksize;

但是pblk是8位的,最多只能支持255内存管理,32位内存空间的话就不能用这个,所以32位寻址的时候,需要修改这部分的东西,我推荐这个部分的内存管理代码可以自己写,反正和操作系统任务调度也没有关系

ucos内存管理原理详解的更多相关文章

  1. ARC内存管理机制详解

    ARC在OC里面个人感觉又是一个高大上的牛词,在前面Objective-C中的内存管理部分提到了ARC内存管理机制,ARC是Automatic Reference Counting---自动引用计数. ...

  2. object-c(oc)内存管理机制详解

    1.内存的创建和释放 让我们以Object-c世界中最最简单的申请内存方式展开,谈谈关于一个对象的生命周期.首先创建一个对象: 1 2 3 //“ClassName”是任何你想写的类名,比如NSStr ...

  3. iOS- 非ARC的项目内存管理细节详解(实战)

    1.前言 接上文:iOS- 如何将非ARC的项目转换成ARC项目(实战) 2.内存管理时相关的配置 当我们把将非ARC的内存管理都管理好后,发现在做有些操作的时候内存还是在一直的缓慢增加 比如做一个最 ...

  4. Namenode HA原理详解(脑裂)

    转自:http://blog.csdn.net/tantexian/article/details/40109331 Namenode HA原理详解 社区hadoop2.2.0 release版本开始 ...

  5. 转 Linux内存管理原理

    Linux内存管理原理 在用户态,内核态逻辑地址专指下文说的线性偏移前的地址Linux内核虚拟3.伙伴算法和slab分配器 16个页面RAM因为最大连续内存大小为16个页面 页面最多16个页面,所以1 ...

  6. NFS原理详解

    NFS原理详解 摘自:http://atong.blog.51cto.com/2393905/1343950 2013-12-23 12:17:31 标签:linux NFS nfs原理详解 nfs搭 ...

  7. 0614MySQL的InnoDB索引原理详解

    转自http://www.cnblogs.com/shijingxiang/articles/4743324.html MySQL的InnoDB索引原理详解 http://www.admin10000 ...

  8. CentOS 6.5 iptables原理详解以及功能说明

    CentOS 6.5 iptables原理详解以及功能说明 来源 https://blog.51cto.com/tanxw/1389114 前言 iptables其实就是Linux下的一个开源的信息过 ...

  9. 【转贴】内存重要参数详解 RAS CAS

    内存重要参数详解 RAS CAS 分类: LINUX 2014-09-12 09:41:58 原文地址:内存重要参数详解 RAS CAS 作者:Reny http://blog.chinaunix.n ...

随机推荐

  1. IDA_Python命令行使用

    Python>import idaapi Python>hex(idaapi.get_first_cref_from(here()))

  2. HTML5新特性总览

    html5的革新带来了更多的功能,简单的一个标签遍可以做到很多事情,例如 (1)canvas画图,vedio视屏,geolocation等等新标签. 如何检查浏览器是否支持这些新特性? 这样就足够,改 ...

  3. hdu 2647 Reward(拓扑排序,反着来)

    Reward Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submis ...

  4. UVA - 437 The Tower of Babylon(dp-最长递增子序列)

    每一个长方形都有六种放置形态,其实可以是三种,但是判断有点麻烦直接用六种了,然后按照底面积给这些形态排序,排序后就完全变成了LIS的问题.代码如下: #include<iostream> ...

  5. HDU 4738 Caocao's Bridges(割边)

    乍一看一个模板题,仔细一看还是模板题,但是三个坑.1,不是连通图,放0个.2 守卫为0,放1个. 3注意重边. #include<iostream> #include<cstdio& ...

  6. Class.forName() 初始化、Thread.currentThread().getContextClassLoader().getResourceAsStream

    Class.forName() 和 ClassLoader.loadClass()的区别? Class.forName() 和 Class.forName().NewInstance()的区别? Cl ...

  7. 在ubuntu server 上记录和查看cron日志

    1.安装rsyslog apt-get install rsyslog 2.修改它的配置文件 vi /etc/rsyslog.d/50-default.conf 把cron那一行注释去掉 3.然后重启 ...

  8. mysql笔记6之数据类型

    1 区别一: varchar:可变长度的字符串.根据添加的数据长度决定占用的字符数 char:固定长度的字符串 2区别二 int:没有限制 int(4):限制为4 3 区别三: 日期: date    ...

  9. MVC3 Razor 根据不同页面使用不同Layout

    _ViewStart.cshtml运行于每一Page前, 所以通常在这里先设置Layout   下面代码为特定的controller指定Index,Edit,Create的模板 即Index对应  _ ...

  10. html常见标签使用

    <body> <!--标题标签--> <h1></h1> <h2></h2> <h3></h3> < ...