99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

uCos-II學(xué)習(xí)之內(nèi)存管理詳解

發(fā)布時間:2017-05-18 22:27  回復(fù):0  查看:2590   最后回復(fù):2017-05-18 22:27  
ucos 系統(tǒng)由于構(gòu)思巧妙,結(jié)構(gòu)精簡設(shè)計(jì),可讀性強(qiáng),同時又具有實(shí)時性操作系統(tǒng)大部分的優(yōu)點(diǎn),在 物聯(lián)網(wǎng)開發(fā)中應(yīng)用非常廣泛。
之前一直都只是會用ucos 卻沒有好好研究過它,最近項(xiàng)目中要用到了 ucos-II 所以順便研究了一番,突然發(fā)現(xiàn) ucos-II 的內(nèi)存管理寫得非常巧妙。
廢話不多說,直接上代碼:
先看一個內(nèi)存塊結(jié)構(gòu)體
1 typedef struct os_mem {                   /* MEMORY CONTROL BLOCK                                      */
2     void   *OSMemAddr;                    /* Pointer to beginning of memory partition                  */
3     void   *OSMemFreeList;                /* Pointer to list of free memory blocks                     */
4     INT32U  OSMemBlkSize;                 /* Size (in bytes) of each block of memory                   */
5     INT32U  OSMemNBlks;                   /* Total number of blocks in this partition                  */
6     INT32U  OSMemNFree;                   /* Number of memory blocks remaining in this partition       */
7 #if OS_MEM_NAME_EN > 0u
8     INT8U  *OSMemName;                    /* Memory partition name                                     */
9 #endif
10 } OS_MEM;
其中 OSMemAddr 指向一塊內(nèi)存的起始地址;
OSMemFreeList 指向一個可利用的空塊的地址;
再看看內(nèi)存的分配函數(shù)
1 OS_MEM  *OSMemCreate (void   *addr,
2                       INT32U  nblks,
3                       INT32U  blksize,
4                       INT8U  *perr)
5 {
6     OS_MEM    *pmem;
7     INT8U     *pblk;
8     void     **plink;
9     INT32U     loops;
10     INT32U     i;
11 #if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
12     OS_CPU_SR  cpu_sr = 0u;
13 #endif
14
15
16
17 #ifdef OS_SAFETY_CRITICAL
18     if (perr == (INT8U *)0) {
19         OS_SAFETY_CRITICAL_EXCEPTION();
20     }
21 #endif
22
23 #ifdef OS_SAFETY_CRITICAL_IEC61508
24     if (OSSafetyCriticalStartFlag == OS_TRUE) {
25         OS_SAFETY_CRITICAL_EXCEPTION();
26     }
27 #endif
28
29 #if OS_ARG_CHK_EN > 0u
30     if (addr == (void *)0) {                          /* Must pass a valid address for the memory part.*/
31         *perr = OS_ERR_MEM_INVALID_ADDR;
32         return ((OS_MEM *)0);
33     }
34     if (((INT32U)addr & (sizeof(void *) - 1u)) != 0u){  /* Must be pointer size aligned                */
35         *perr = OS_ERR_MEM_INVALID_ADDR;
36         return ((OS_MEM *)0);
37     }
38     if (nblks < 2u) {                                 /* Must have at least 2 blocks per partition     */
39         *perr = OS_ERR_MEM_INVALID_BLKS;
40         return ((OS_MEM *)0);
41     }
42     if (blksize < sizeof(void *)) {                   /* Must contain space for at least a pointer     */
43         *perr = OS_ERR_MEM_INVALID_SIZE;
44         return ((OS_MEM *)0);
45     }
46 #endif
47     OS_ENTER_CRITICAL();
48     pmem = OSMemFreeList;                             /* Get next free memory partition                */
49     if (OSMemFreeList != (OS_MEM *)0) {               /* See if pool of free partitions was empty      */
50         OSMemFreeList = (OS_MEM *)OSMemFreeList->OSMemFreeList;
51     }
52     OS_EXIT_CRITICAL();
53     if (pmem == (OS_MEM *)0) {                        /* See if we have a memory partition             */
54         *perr = OS_ERR_MEM_INVALID_PART;
55         return ((OS_MEM *)0);
56     }
57     plink = (void **)addr;                            /* Create linked list of free memory blocks      */
58     pblk  = (INT8U *)addr;
59     loops  = nblks - 1u;
60     for (i = 0u; i < loops; i++) {
61         pblk +=  blksize;                             /* Point to the FOLLOWING block                  */
62        *plink = (void  *)pblk;                        /* Save pointer to NEXT block in CURRENT block   */
63         plink = (void **)pblk;                        /* Position to  NEXT      block                  */
64     }
65     *plink              = (void *)0;                  /* Last memory block points to NULL              */
66     pmem->OSMemAddr     = addr;                       /* Store start address of memory partition       */
67     pmem->OSMemFreeList = addr;                       /* Initialize pointer to pool of free blocks     */
68     pmem->OSMemNFree    = nblks;                      /* Store number of free blocks in MCB            */
69     pmem->OSMemNBlks    = nblks;
70     pmem->OSMemBlkSize  = blksize;                    /* Store block size of each memory blocks        */
71     *perr               = OS_ERR_NONE;
72     return (pmem);
73 }
這個函數(shù)把addr 指向的一塊連續(xù)的內(nèi)存劈成 nblks blksize 大小的內(nèi)存塊。里面利用了一個技巧:在 60-64 行的這個 for 循環(huán)里面把每個內(nèi)存塊的首地址保存在它的上一個內(nèi)存塊的首地址空間里面。 67 行把 pmem 里面的 OSMemFreeList 指向第一個空塊的地址 ( 當(dāng)前空塊的第一個地址保存的是下一個空塊的地址 ) 。
再看看內(nèi)存獲取函數(shù)
1 void  *OSMemGet (OS_MEM  *pmem,
2                  INT8U   *perr)
3 {
4     void      *pblk;
5 #if OS_CRITICAL_METHOD == 3u                          /* Allocate storage for CPU status register      */
6     OS_CPU_SR  cpu_sr = 0u;
7 #endif
8
9
10
11 #ifdef OS_SAFETY_CRITICAL
12     if (perr == (INT8U *)0) {
13         OS_SAFETY_CRITICAL_EXCEPTION();
14     }
15 #endif
16
17 #if OS_ARG_CHK_EN > 0u
18     if (pmem == (OS_MEM *)0) {                        /* Must point to a valid memory partition        */
19         *perr = OS_ERR_MEM_INVALID_PMEM;
20         return ((void *)0);
21     }
22 #endif
23     OS_ENTER_CRITICAL();
24     if (pmem->OSMemNFree > 0u) {                      /* See if there are any free memory blocks       */
25         pblk                = pmem->OSMemFreeList;    /* Yes, point to next free memory block          */
26         pmem->OSMemFreeList = *(void **)pblk;         /*      Adjust pointer to new free list          */
27         pmem->OSMemNFree--;                           /*      One less memory block in this partition  */
28         OS_EXIT_CRITICAL();
29         *perr = OS_ERR_NONE;                          /*      No error                                 */
30         return (pblk);                                /*      Return memory block to caller            */
31     }
32     OS_EXIT_CRITICAL();
33     *perr = OS_ERR_MEM_NO_FREE_BLKS;                  /* No,  Notify caller of empty memory partition  */
34     return ((void *)0);                               /*      Return NULL pointer to caller            */
35 }
這個函數(shù)除了紅色標(biāo)出來的這幾行代碼其它都不重要,在這幾行代碼里面獲取OSMemFreeList 指向的內(nèi)存塊的地址之后把這個地址 return 出去使用。
那么問題來了:為什么沒有遍歷空塊的過程?
原因就在于上面所提到的那種巧妙地方法,每個內(nèi)存塊的前32 位保存的是下一個空塊的地址,在獲取到 OSMemFreeList OSMemFreeList 指針應(yīng)該要指向下一個空塊,而下一個空塊就在當(dāng)前獲取到的空塊的第一個地址里面,所以在 26 行把 OSMemFreeList 指針指向了當(dāng)前獲取到的內(nèi)存塊的第一個地址所指向的內(nèi)存塊處。
最后就是內(nèi)存釋放函數(shù)
1 INT8U  OSMemPut (OS_MEM  *pmem,
2                  void    *pblk)
3 {
4 #if OS_CRITICAL_METHOD == 3u                     /* Allocate storage for CPU status register           */
5     OS_CPU_SR  cpu_sr = 0u;
6 #endif
7
8
9
10 #if OS_ARG_CHK_EN > 0u
11     if (pmem == (OS_MEM *)0) {                   /* Must point to a valid memory partition             */
12         return (OS_ERR_MEM_INVALID_PMEM);
13     }
14     if (pblk == (void *)0) {                     /* Must release a valid block                         */
15         return (OS_ERR_MEM_INVALID_PBLK);
16     }
17 #endif
18     OS_ENTER_CRITICAL();
19     if (pmem->OSMemNFree >= pmem->OSMemNBlks) {  /* Make sure all blocks not already returned          */
20         OS_EXIT_CRITICAL();
21         return (OS_ERR_MEM_FULL);
22     }
23     *(void **)pblk      = pmem->OSMemFreeList;   /* Insert released block into free block list         */
24     pmem->OSMemFreeList = pblk;
25     pmem->OSMemNFree++;                          /* One more memory block in this partition            */
26     OS_EXIT_CRITICAL();
27     return (OS_ERR_NONE);                        /* Notify caller that memory block was released       */
28 }
同樣,最關(guān)鍵的代碼在紅色部分。首先把要釋放的內(nèi)存塊的首地址指向OSMemFreeList 指向的地址 ( 這個地址就是下一個空塊的首地址 ) ,之后把 OSMemFreeList 指向剛剛釋放的內(nèi)存塊的首地址。只用了一行代碼就把一個要釋放的內(nèi)存塊插入了空塊鏈表,再調(diào)整 OSMemFreeList 指針指向剛釋放的內(nèi)存塊,就是這么簡單粗暴?。?!
一句話總結(jié):ucos-II 的內(nèi)存管理利用內(nèi)存塊的首地址保存下一個空塊的首地址的方式把所有空塊鏈接起來。至少有一個好處,那就是在獲取內(nèi)存塊的時候少了一個對整個內(nèi)存塊進(jìn)行遍歷找出空塊的過程!
來源:博客園
您還未登錄,請先登錄

熱門帖子

最新帖子

?