咱们在写应用程序的进程中一般都是选用一个malloc/free系列函数进行内存的办理,这样分配的内存空间是从应用程序的栈空间分配处理,一般来说咱们在写程序的进程中要对内存空间进行当令的开释,才不至于导致栈空间的缺乏,当然这样也会导致内存废物的发生,由于不同巨细的内存分配由于对齐等原因导致许多的内存不能再运用,从而使得体系的可用内存越来越小,因而在实时操作体系中一般都需求创立自己的内存办理操作。
/*
关于内存操控块的结构体,
用来盯梢每一个内存分区
每一个分区能够分红许多个小的内存块
每一个内存块的巨细都是相同的
*/
#if (OS_MEM_EN > 0) && (OS_MAX_MEM_PART > 0)
typedef struct { /* MEMORY CONTROL BLOCK */
/*内存的开始地址*/
void *OSMemAddr; /* Pointer to beginning ofmemorypartition */
/*
链表指针,
能够快速的完结内存的操控
*/
void *OSMemFreeList; /* Pointer to list of free memory blocks */
/*每一个内存块的巨细*/
INT32U OSMemBlkSize; /* Size (in bytes) of each block of memory */
/*存在的内存块数量*/
INT32U OSMemNBlks; /* Total number of blocks in this partition */
/*闲暇的内存空间*/
INT32U OSMemNFree; /* Number ofmemoryblocks remaining in this partition */
} OS_MEM;
根本的完结思维便是将内存分区分解成许多的巨细相同的内存块,然后OSMemFreeList将一切的内存块链接起来,可是此处的链接与咱们常用的链表存在必定的不同,这也是内存办理中常用的技巧之一,即在当时块的开始地址处寄存下一个内存块的地址,这样就能比较快速的完结内存的办理。在uc/os-II的内存办理代码的OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)函数中存在一些代码难点。特别是强制类型转化的运用,在uc/os-II中咱们看见了很多的强制类型转化问题,下面就做一下扼要的剖析:
OS_MEM *OSMemCreate (void *addr, INT32U nblks, INT32U blksize, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPUstatusregister */
OS_CPU_SR cpu_sr;
#endif
OS_MEM *pmem;
INT8U *pblk;
void **plink;
INT32U i;
/*检测参数的正确性*/
#if OS_ARG_CHK_EN > 0
if (addr == (void *)0) { /* Must pass a valid address for the memory part. */
*err = OS_MEM_INVALID_ADDR;
return ((OS_MEM *)0);
}
if (nblks < 2) { /* Must have at least 2 blocks per partition */
*err = OS_MEM_INVALID_BLKS;
return ((OS_MEM *)0);
}
if (blksize < sizeof(void *)) { /* Must contain space for at least a pointer */
*err = OS_MEM_INVALID_SIZE;
return ((OS_MEM *)0);
}
#endif
OS_ENTER_CRITICAL();
/*得到闲暇的内存操控块*/
pmem = OSMemFreeList; /* Get next free memory partition */
/*更新内存操控块链表*/
if (OSMemFreeList != (OS_MEM *)0) { /* See if pool of free partitions was empty */
OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
}
OS_EXIT_CRITICAL();
if (pmem == (OS_MEM *)0) { /* See if we have a memory partition */
*err = OS_MEM_INVALID_PART;
return ((OS_MEM *)0);
}
/*
将一个分区的各个内存小块链接起来,
构成一个链表
*/
plink = (void **)addr; /* Create linked list of free memoryblocks */
/*得到一个固定的*/
pblk = (INT8U *)addr + blksize;
for (i = 0; i < (nblks - 1); i++) {
/*在当时的地址处保存下一个内存块的地址*/
*plink = (void *)pblk;
/*将指针指向下一个内存块*/
plink = (void **)pblk;
/*得到第三个内存块的地址*/
pblk = pblk + blksize;
}
/*
将最终一个内存块的下一个地址设置为NULL;
*/
*plink = (void *)0; /* Last memoryblockpoints to NULL */
/*得到内存分区的开始地址*/
pmem->OSMemAddr = addr; /* Store start address ofmemorypartition */
/*
将内存块的链表头指向当时地址
经过链表能够快速的找到下一个内存块的地址
只需求对链表取地址,
然后将指针指向该地址就能完结快速的切换
*/
pmem->OSMemFreeList = addr; /* Initialize pointer to pool of free blocks */
/*闲暇的内存块*/
pmem->OSMemNFree = nblks; /* Store number of free blocks in MCB */
/*内存的总块数*/
pmem->OSMemNBlks = nblks;
/*内存块的巨细*/
pmem->OSMemBlkSize = blksize; /* Store block size of eachmemoryblocks */
*err = OS_NO_ERR;
return (pmem);
}
上面的代码大致的意思便是完结内存块的链接以及内存分区操控单元的初始化操作,可是有几句代码存在必定的了解难度。
plink = (void **)addr; /* Create linked list of free memory blocks */
pblk = (INT8U *)addr + blksize;
for (i = 0; i < (nblks - 1); i++) {
*plink = (void *)pblk;
plink = (void **)pblk;
pblk = pblk + blksize;
}
*plink = (void *)0; /* Lastmemoryblockpoints to NULL */
下面几句代码中存在很多的强制类型转化,咱们一句一句的剖析,plink=(void**)addr的意思是将传递进来的地址强制转化,原因是由于plink是一个存储在函数栈中的变量,它指向了addr指向的地址,而该地址处将来存储的也是一个地址,因而能够看做二维指针,而addr仅仅一维指针,因而需求强制类型转化为二维指针。
引证:在声明的时分,plink是二维指针,在这里将addr强制的转化成二维指针再赋值给plink的原因是:让addr曾经指向的内容让编译器解说成地址,也便是一个指针,假如不做这个强制转化,曾经addr指向的内容就不是一个地址,也便是不是指针,在这个函数傍边,咱们想把addr指向的二维数组,切割成巨细相同的若干块,就有必要用指针把它们链接起来,所以将addr强制转化成二维指针,然后赋值给plink,然后让plink去履行衔接的操作,也便是在曾经addr指向的当地放上指针;plink自身是寄存在栈上的,plink这个符号的值是指向addr的,*plink便是取plink指向地址单元的内容,而 plink指向地址单元的内容是一个地址,便是一个指针,plink指向地址单元的内容也便是addr指向地址单元的内容,但由于addr是一维指针,所以它指向的内容不会被解说成一个地址,而是一般的内容。现在*plink便是把addr地点存储单元的内容解说成一个指针,而且将下一个block的首地址赋值给此存储单元,了解了这点就能够了解下面的源代码了,一起对C里边指针的概念又有了进一步的知道。http://blog.csdn.net/uestczhangchao/article/details/5589476
pblk=(INT8U*)addr+blksize;这句代码其间暗含了咱们对指针加减操作的根本了解,由于在uc/OS-II中是依照字节作为内存块散布的,所以进行了INT8U*的强制类型转化,由于只要这样才干确保addr+blksize的操作是添加多少个字节的数据。由于C言语中指针的加减是与其指向的类型的内存空间密切相关的,比方int * p = 0; p ++;此刻的p = 4;而当char *p = 0; p ++; 此刻的p = 1;这就说明晰指针的加减有必要留意数据的类型,而不能直接对void*类型的指针进行加减操作。
*plink=(void*)pblk;由于plink是一个栈中变量,而对plink取进行解引证,实际上便是得到addr的值,可是*plink是一个地址,仍是一个指针,因而需求强制类型转化。
plink=(void**)pblk;上面的代码现已剖析。
根本的思维便是需求留意常数转化为指针的方式方法:int* p = (int *)0x45342341;int **p = (int **)0x45342341;指针的引进首要便是为了处理内存问题,因而对内存的办理直接表现了对指针的了解深度。