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

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. 在WIN7/8下把XP装入VHD (上)

    系统平台:win8.1 操作目的:工作中需要使用一个只能在winxp下运行的软件,但我平时都用win8.1,也不想弄个麻烦的双系统.在无忧论坛研究了两天后找到个比较好的办法,在VHD里装个window ...

  2. ubuntu 常用命令记录

    1.# 表示权限用户(如:root),$ 表示普通用户  开机提示:Login:输入用户名  password:输入口令   用户是系统注册用户成功登陆后,可以进入相应的用户环境.  退出当前shel ...

  3. ant脚本

    jenkins在调用ant脚本时会遇到ant中的目标没有成功,但是最后的build状态却是success,如下图所示:代码中缺少一个},编译发生错误,最后的build成功. 解决方案:在关键的targ ...

  4. shell写多行到文件中

    用cat或者echo命令输入多行数据到指定文本 #!/bin/sh ( cat <<EOF start() { echo "start" } EOF ) > Ma ...

  5. lucene索引合并与增量索引

    利用 Lucene,在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率.当你需要索引大量的文件时,你会注意到索引过程的瓶颈是在往磁盘上写索引文件的过程中.为了解决这个问题, Lucene ...

  6. android:contentDescription的作用是什么

    在写Android的XML布局文件时,在ImageView或ImageButton中经常会碰到一个提示: Missing contentDescription attribute on image. ...

  7. hdu_5738_Eureka(脑洞)

    题目链接:hdu_5738_Eureka 题意: 这题感觉说不清楚,坑点有点坑,一不小心就会推出错误的公式,然后最重要的是你还不知道你推错了 题解: 这里贴一个官方的题解 Eureka xjb推导一下 ...

  8. Android AudioPolicyService和AudioPolicyManager

    AudioPolicyService是Android音频系统的两大服务之一,另一个服务是AudioFlinger,这两大服务都在系统启动时有 MediaSever加载,加载的代码位于:framewor ...

  9. Ubuntu将新增磁盘挂载到home下

    home磁盘空间不足,其他闲置硬盘是原来windows的,不能直接使用(磁盘格式及权限等原因),比如编译安卓源码等. 这样的话就需要将新的磁盘格式化成fat32后挂载到/home下的一个目录,这样就可 ...

  10. 怎样让外界无法改变自定义view的尺寸大小

    重写setFrame和setBounds方法即可. + (instancetype)testView { return [[self alloc] init]; } - (void)setFrame: ...