1、固定内存池管理实验

内存管理是操作系统的一个基础功能。uTenux的内存池管理函数提供了基于软件的内存池管理和内存块分配管理。uTenux的内存池有固定大小的内存池和大小可变的内存池之分,它们被看成是互相独立的对象,需要不同的系统调用集来进行操作。

内存池管理函数管理的内存全部包含在系统空间以内。

1、固定尺寸内存池实验

固定尺寸内存池是一个用来动态管理固定尺寸内存块的对象。每个固定尺寸内存池都有一个用作固定尺寸内存池的内存空间(简称为内存池区)和一个等待内存块分配的任务队列。

uTenux提供了五个供操作固定内存池的API,分别用于创建、删除、获取、释放、查询内存池状态。

创建固定尺寸内存池,需要提供一个T_CMPF类型的结构体。定义如下:

typedef    struct t_cmpf {
VP exinf; /* 扩展信息*/
ATR mpfatr; /* 内存池属性*/
W mpfcnt; /* 创建的内存池块数*/
W blfsz; /* 每块的大小(byte) */
UB dsname[]; /* Object name */
VP bufptr; /* User buffer */
} T_CMPF;

内存池属性mpfatr是的定义如下:

mpfatr:=(TA_TFIFO||TA_TPRI)|TA_USERBUF|TA_DSNAME|(TA_RNG0||TA_RNG1 ||TA_RNG2||TA_RNG3)

TA_TFIFO 等待内存分配的任务按FIFO的顺序排队

TA_TPRI 等待内存分配的任务按优先级顺序排队

TA_RNGn 内存访问权设置成保护级别n

TA_USERBUF 指示系统使用用户指定的内存空间

TA_DSNAME 设定DS对象名

由于uTenux没有使用硬件的内存保护功能,TA_RNGn 只能是TA_RNG0。TA_USERBUF是不使用OS提供的内存空间时候使用的。TA_DSNAME基本没什么用。

获取内存池函数:ER ercd= tk_get_mpf(ID mpfid,VP *p_blf,TMO tmout);中,p_blf为获取的内存块的起始地址。为VP类型,即一个void*的指针。使用时需要注意。

【实验描述】

1、创建两个任务一个包含5块区域的内存池。

2、启动TaskB,在TaskB中启动TaskA,TaskA开始执行就立即休眠。等待TaskB唤醒

3、TaskB继续执行。先输出当前可用内存块数目,申请一块内存后再次输出内存块数目。

4、最后将一段数据放入这块内存。之后唤醒TaskA。

5、TaskA输出由TaskB放入内存块的数据之后,释放内存块。再次输出可用内存块数。。然后进入休眠状态,TaskB继续执行。

【代码及输出】

固定内存池使用:

#include "MpfSample.h"

void MpfSampleTaskA(W stacd,VP exinf);
void MpfSampleTaskB(W stacd,VP exinf);
void MpfSamplePutCnt(void);
static ID TaskID_A;
static ID TaskID_B;
static ID mpfid;
static VP blf=NULL; ER MpfSample( void)
{
ER ercd = E_OK;
T_CTSK ctsk;
T_CMPF cmpf; tm_putstring((UB*)"Mempool fix sample create Task A;\n");
ctsk.exinf = (VP)NULL;
ctsk.tskatr = TA_HLNG | TA_RNG0;
ctsk.task = MpfSampleTaskA;
ctsk.itskpri = ;
ctsk.stksz = ;
TaskID_A = tk_cre_tsk(&ctsk);
if(TaskID_A < E_OK) {
ercd=TaskID_A;
return ercd;
} tm_putstring((UB*)"Mempool fix sample create Task B;\n");
ctsk.task = MpfSampleTaskB;
ctsk.itskpri = ;
TaskID_B = tk_cre_tsk(&ctsk);
if(TaskID_B < E_OK) {
ercd=TaskID_B;
return ercd;
} tm_putstring((UB*)"Mempool fix sample create a mempoolf;\n");
cmpf.bufptr = NULL;
cmpf.exinf = (VP)NULL;
cmpf.blfsz = ; //100Byte
cmpf.mpfcnt = ; //5块
cmpf.mpfatr = TA_TFIFO | TA_RNG0; //内存池属性,先到先得 不使用保护
mpfid = tk_cre_mpf(&cmpf); tm_putstring((UB*)"Mempool fix sample create a mempoolf successfully;\n");
MpfSamplePutCnt(); tm_putstring((UB*)"Mempool fix sample start Task B;\n");
tk_sta_tsk(TaskID_B,);
return TRUE;
} void MpfSampleTaskA(W stacd,VP exinf)
{
tm_putstring((UB*)"Task A now enter sleep mode\n");
tk_slp_tsk(-);
while()
{
tm_putstring((UB*)"Task A read data from the memory block,that is:\n");
tm_putstring((UB*)blf);
tk_rel_mpf(mpfid,blf);
MpfSamplePutCnt();
tk_slp_tsk(-);
}
} void MpfSampleTaskB(W stacd,VP exinf)
{
B* buf = "this is utenux\n";
B blfadd[];
tm_putstring((UB*)"Task B now start Task A\n");
tk_sta_tsk(TaskID_A,);
tm_putstring((UB*)"*****************************************\n");
while()
{
MpfSamplePutCnt();
tm_putstring((UB*)"Task B now get a block of memory\n");
if(E_OK == tk_get_mpf(mpfid,&blf,-)) //申请内存块
{
MpfSamplePutCnt();
tm_putstring((UB*)"Task B get memory block sucessfully\nmemory addressis 0x");
ltostr((UW)blf,blfadd,,);
tm_putstring((UB*)blfadd); //以字符串形式输出地址
tm_putstring((UB*)"\n*****************************************\n");
memcpy(blf,buf,strlen(buf)+);
}
else
{
tm_putstring((UB*)"Task B failed get memory\n");
break;
}
tm_putstring((UB*)"Task B now wake up Task A\n");
tk_wup_tsk(TaskID_A);
Delay(0x1000000);
}
} void MpfSamplePutCnt(void)
{
B frbcnt[];
T_RMPF rmpf; tm_putstring((UB*)"Now Free memory block number is ");
tk_ref_mpf(mpfid, &rmpf);
ltostr(rmpf.frbcnt,frbcnt,,);
tm_putstring((UB*)frbcnt);
tm_putstring((UB*)"\n");
}

输出:

----------------------------------------------------
        micro Tenux Version 1.6.00(build 0180)     
            Supported MCU is ST STM32F407VG        
  Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd. 
----------------------------------------------------

Mempool fix sample create Task A;
Mempool fix sample create Task B;
Mempool fix sample create a mempoolf;
Mempool fix sample create a mempoolf successfully;
Now Free memory block number is 5
Mempool fix sample start Task B;
Task B now start Task A
Task A now enter sleep mode
*****************************************
Now Free memory block number is 5
Task B now get a block of memory
Now Free memory block number is 4
Task B get memory block sucessfully
memory addressis 0x20002634
*****************************************
。。。。。。。。。。。

2、可变内存池实验

预备知识:C语言中的内存块操作函数

1、memcpy
原型:void *memcpy(void *dest, const void *src, size_t n);
功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
2、memmove

原型:void *memmove( void* dest, const void* src,size_tcount );

头文件:<string.h>

功能:由src所指内存区域复制count个字节到dest所指内存区域。

说明memmove用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。

3、memcmp
int memcmp(const void *buf1, const void *buf2, unsigned int count);
比较内存区域buf1和buf2的前count个字节。

当buf1<buf2时,返回值<0

当buf1=buf2时,返回值=0

当buf1>buf2时,返回值>0

4、memchr

原型:extern void *memchr(const void *buf, int ch, size_t count);

用法:#include <string.h>

功能:从buf所指内存区域的前count个字节查找字符ch。

说明:当第一次遇到字符ch时停止查找。如果成功,返回指向字符ch的指针;否则返回NULL。

5、memset

void *memset(void *s, int ch, size_t n);

函数解释:将s中前n个字节(typedef unsigned int size_t)用 ch 替换并返回s。

作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法。

可变尺寸内存池是一个用来动态管理任何大小的内存块的对象。与固定尺寸内存池一样,每个可变尺寸内存池都有一个用作可变尺寸内存池的内存空间和一个等待内存块分配的任务队列。

可变尺寸内存池管理SVC:

创建可变尺寸内存池:tk_cre_mpl

需要提供参数T_CMPL的定义如下:

typedef    struct t_cmpl {
VP exinf; /* 扩展属性*/
ATR mplatr; /* 内存池属性 */
W mplsz; /* 内存池的大小 (byte) */
UB dsname[]; /* Object name */
VP bufptr; /* User buffer */
} T_CMPL;

内存池属性的定义:

mplatr:=(TA_TFIFO||TA_TPRI)|TA_USERBUF|TA_DSNAME|(TA_RNG0||TA_RNG1||TA_RNG2 ||TA_RNG3)

TA_TFIFO 等待内存分配的任务按FIFO的顺序排队

TA_TPRI 等待内存分配的任务按优先级顺序排队

TA_RNGn 内存访问权设置成保护级别n

TA_USERBUF 指示系统使用用户指定的内存空间

TA_DSNAME 设定DS对象名

可以发现,uTenux中各个对象的属性定义是很相似的:

1、两种排队顺序TA_TFIFO和TA_TPRI

2、内存保护级别TA_RNGn 必须是TA_RNG0

3、TA_DSNAME对象名

4、TA_USERBUF 用户缓存

之后就不列出来这东西了。

至于申请,释放都比较简单,这里不一一列出了。

【实验描述】

本实验参考源码包中的09.mempoolv

1、首先创建两个人物一个大小512字节的内存池。然后启动任务A,任务A自动休眠等待唤醒。之后启动任务B。

2、任务B首先输出可用内存数,之后申请128Byte内存,再次输出可用内存数。

3、任务B将申请到的内存清空,将数据放入。之后唤醒任务A。

4、任务A优先级高,开始执行。

5、任务A首先输出任务B放入内存块的数据,任何释放这个内存块。

6、最后任务A再次休眠,任务B开始循环执行。

【实验代码和输出】

#include "MempoolvSample.h"

void MplSampleTaskA(W stacd,VP exinf);
void MplSampleTaskB(W stacd,VP exinf);
void MplSamplePutCnt(void);
static ID TaskID_A;
static ID TaskID_B;
static ID mplid;
static VP blf; ER MplSample( void)
{
ER ercd = E_OK;
T_CTSK ctsk;
T_CMPL cmpl; tm_putstring((UB*)"Mempool variable sample create Task A;\n");
ctsk.exinf = (VP)NULL;
ctsk.tskatr = TA_HLNG | TA_RNG0;
ctsk.task = MplSampleTaskA;
ctsk.itskpri = ;
ctsk.stksz = ;
TaskID_A = tk_cre_tsk(&ctsk);
if(TaskID_A < E_OK) {
ercd=TaskID_A;
PutErcd(ercd);
return ercd;
} tm_putstring((UB*)"Mempool variable sample create Task B;\n");
ctsk.exinf = (VP)NULL;
ctsk.tskatr = TA_HLNG | TA_RNG0;
ctsk.task = MplSampleTaskB;
ctsk.itskpri = ;
ctsk.stksz = ;
TaskID_B = tk_cre_tsk(&ctsk);
if(TaskID_B < E_OK) {
ercd=TaskID_B;
PutErcd(ercd);
return ercd;
} //自己写
tm_putstring((UB*)"Mempool variable sample create a mempool variable;\n"); cmpl.bufptr = NULL;
cmpl.exinf =(VP)NULL;
cmpl.mplatr = TA_TFIFO | TA_RNG0;
cmpl.mplsz = ;
mplid = tk_cre_mpl(&cmpl);
if(E_OK < mplid)
{
tm_putstring((UB*)"Mempool variable sample create a mempool successfully;\n");
} tm_putstring((UB*)"Mempool variable sample start Task A;\n");
tk_sta_tsk(TaskID_A,);
tm_putstring((UB*)"Mempool variable sample start Task B;\n");
tk_sta_tsk(TaskID_B,); return TRUE;
} void MplSampleTaskA(W stacd,VP exinf)
{
tm_putstring((UB*)"Task A enter sleep status;\n");
tk_slp_tsk(-);
while()
{
tm_putstring((UB*)"Task A print the contents of the memory block;\n");
tm_putstring((UB*)blf);
tm_putstring((UB*)"Task A release mpl,;\n");
tk_rel_mpl(mplid,blf);
MplSamplePutCnt(); tk_slp_tsk(-);
}
} void MplSampleTaskB(W stacd,VP exinf)
{
B* buf = "this is an utenux programme\n";
B* blfadd[];//用于存放地址转换来的字符串 tm_putstring((UB*)"this is in task b\n");
while()
{
MplSamplePutCnt(); //输出申请mpl之前的可用内存字节数
if(E_OK == tk_get_mpl(mplid,,&blf,-))
{
MplSamplePutCnt();
memset(blf,,);//清除掉获取的内存中所有数据
memcpy(blf,buf,strlen(buf)); }
Delay(0x1000000);
tm_putstring((UB*)"Task B wake up Task A\n");
tk_wup_tsk(TaskID_A);
}
} void MplSamplePutCnt(void)
{
B frsz[];
T_RMPL rmpl; tm_putstring((UB*)"Now Free memory number is ");
tk_ref_mpl(mplid, &rmpl);
ltostr(rmpl.frsz,frsz,,);
tm_putstring((UB*)frsz);
tm_putstring((UB*)"B\n");
}

输出:
----------------------------------------------------
        micro Tenux Version 1.6.00(build 0180)     
            Supported MCU is ST STM32F407VG        
  Copyright(c) 2008-2013 by Dalian uLoong Co.,Ltd. 
----------------------------------------------------

Mempool variable sample create Task A;
Mempool variable sample create Task B;
Mempool variable sample create a mempool variable;
Mempool variable sample create a mempool successfully;
Mempool variable sample start Task A;
Task A enter sleep status;
Mempool variable sample start Task B;
this is in task b
Now Free memory number is 512B
Now Free memory number is 376B
Task B wake up Task A
Task A print the contents of the memory block;
this is an utenux programme
Task A release mpl,;
Now Free memory number is 512B
。。。。。。

【关于可变内存池使用的内存与生育内存相加不等于总内存数的问题】

我在实验中每次申请128B,剩余可用内存为376B,每次申请都要损失8B内存,释放后还是原来的数目。后来看到这段,算是明白了:

Get memory block,'blksz' must be larger than minimum fragment size and adjusted by ROUNDSZ unit.

#define ROUNDSZ(sz)    (((UW)(sz) + (UW)(ROUNDSIZE-1)) & ~(UW)(ROUNDSIZE-1))

应该是一个内存对齐。申请121~128个block都会剩余376B

每个可变内存池都是一个队列,队列中每块内存大小都是ROUNDSZ。申请内存的时候,只能按照ROUNDSZ大小进行分配。少补多不退。。。

【uTenux实验】内存池管理(固定内存池和可变内存池)的更多相关文章

  1. 【深入理解JAVA虚拟机】第二部分.内存自动管理机制.3.垃圾收集器与内存分配策略

    1.学习目的 当需要排查各种内存溢出. 内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节. Java内存运行时区域的各个部分,其中程序计数 ...

  2. 【uTenux实验】时间管理(系统时间/周期性处理/警报处理)

    1.系统时间管理 系统时间管理函数用来对系统时间进行操作,是OS的一个基础性的东西.个人认为,设置系统时间和获取系统时间对OS来说基本是可有可无的. uTenux提供了三个系统时间相关API.分别用于 ...

  3. LWIP再探----内存堆管理

    LWIP的内存管理主要三种:内存池Pool,内存堆,和C库方式.三种方式中C库因为是直接从系统堆中分配内存空间且易产生碎片因此,基本不会使用,其他两种是LWIP默认全部采用的方式,也是综合效率和空间的 ...

  4. LWIP再探----内存池管理

    这这里是接上一篇内存池管理部分的,这里如果读者一打开memp.c的话会感觉特别那一理解原作者在干嘛,但是看懂了就明白原作者是怎么巧妙的使用了宏.废话不多说先说了下我分析是一下宏的条件是 前提条件MEM ...

  5. 内存分配(new/delete,malloc/free,allocator,内存池)

    以下来源http://www.cnblogs.com/JCSU/articles/1051826.html 程序员们经常编写内存管理程序,往往提心吊胆.如果不想触雷,唯一的解决办法就是发现所有潜伏的地 ...

  6. 关于.NET大数据量大并发量的数据连接池管理

    转自:http://www.cnblogs.com/virusswb/archive/2010/01/08/1642055.html 我以前对.NET连接池的认识是错误的,原来以为在web.confi ...

  7. (转载)JAVA线程池管理

    平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发攻城师却在这个上面吃了不少苦头.怎么做一套简便的线程开发模式 ...

  8. java虚拟机学习-JVM内存管理:深入垃圾收集器与内存分配策略(4)

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来. 概述: 说起垃圾收集(Garbage Collection,下文简称GC),大部分人都把这项 ...

  9. Java线程池管理及分布式Hadoop调度框架搭建

    平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发工程师却在这个上面吃了不少苦头. 怎么做一套简便的线程开发模 ...

随机推荐

  1. preload pic

    http://www.farinspace.com/jquery-image-preload-plugin/

  2. Java—类的封装、继承与多态

    一.类和对象 1.类 类是数据以及对数据的一组操作的封装体. 类声明的格式: 类声明 { 成员变量的声明: 成员方法的声明及实现: } 1.1 声明类 [修饰符] class 类<泛型> ...

  3. github 使用教程初级版

    github 是一个基于 git 的代码托管平台,付费用户可以建私人仓库,免费用户只能使用公共仓库.对于一般人来说公共仓库就已经足够了,而且也没多少代码来管理.下面简单介绍如何使用 github,供初 ...

  4. 读javascript高级程序设计04-canvas

    一.基本用法 1.要使用canvas元素,需要先给定其width和height来设置绘图区域的大小.canvas中间的文本会在浏览器不支持canvas的情况下显示出来. <canvas widt ...

  5. Octopus系列之数据上传格式要求说明

    各个数据列要求 价格列:字符串类型[美元价格] 产品名字:可以支持"/"等字符 分类名字:去空格处理 不得包含"&"符号 主图:一定要有主图列 不为空 ...

  6. C#微信开发-微信JS-SDK(1)之通过config接口注入权限验证配置

    官方文档是微信JS-SDK的使用步骤http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#JSSDK.E4.BD.B ...

  7. Jmeter教程索引

    一.基础部分: 使用Jmeter进行http接口测试 Jmeter之Http Cookie Manager Jmeter之HTTP Request Defaults Jmeter之逻辑控制器(Logi ...

  8. Rhel6-pacemaker+drbd配置文档

    系统环境: rhel6 x86_64 iptables and selinux disabled 主机: 192.168.122.119 server19.example.com 192.168.12 ...

  9. QuartZ.net 常用配置说明

    配置文件说明 app.config中的quartz部分 <quartz> <!-- configure Thread Pool--> <addkey="quar ...

  10. CSS中相对定位与绝对定位

    看了几个讲解定位的博客,觉得还不错,分享之: 博客一:http://blog.sina.com.cn/s/blog_4bcf4a5e010008o0.html 文章中,主要需要参考的有两点: 1,相对 ...