硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5375|回复: 16
收起左侧

[RTOS] RTX5中有个动态内存管理文件rtx_memory.c,可以方便的分别管理RT1052的SDRAM,TCM和OCRAM的内存空间

  [复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107463
QQ
发表于 2018-3-12 01:58:30 | 显示全部楼层 |阅读模式
1、对于动态内存分配管理,在安全关键的项目中切勿使用,因为内存碎片是无法避免的,而且不具有时间确定性。在安全关键的项目中要使用uCOS-II,III中数组方式的内存动态管理。RTX5也是支持这种方式的。
2、早前RTX4中的,我一直在使用,非常不错、像JPEG解码,MP3解码等里面用用,非常爽,就是不支持动态内存剩余返回,新版RTX5中的已经支持了。
3、这个文件可以独立用于裸机例子或者任何其它RTOS中。



  1. /*
  2. * Copyright (c) 2013-2018 Arm Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the License); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * -----------------------------------------------------------------------------
  19. *
  20. * Project:     CMSIS-RTOS RTX
  21. * Title:       Memory functions
  22. *
  23. * -----------------------------------------------------------------------------
  24. */

  25. #include "rtx_lib.h"


  26. //  Memory Pool Header structure
  27. typedef struct {
  28.   uint32_t size;                // Memory Pool size
  29.   uint32_t used;                // Used Memory
  30. } mem_head_t;

  31. //  Memory Block Header structure
  32. typedef struct mem_block_s {
  33.   struct mem_block_s *next;     // Next Memory Block in list
  34.   uint32_t            info;     // Block Info or max used Memory (in last block)
  35. } mem_block_t;

  36. //  Memory Block Info: Length = <31:2>:'00', Type = <1:0>
  37. #define MB_INFO_LEN_MASK        0xFFFFFFFCU     // Length mask
  38. #define MB_INFO_TYPE_MASK       0x00000003U     // Type mask

  39. //  Memory Head Pointer
  40. __STATIC_INLINE mem_head_t *MemHeadPtr (void *mem) {
  41.   //lint -e{9079} -e{9087} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
  42.   return ((mem_head_t *)mem);
  43. }

  44. //  Memory Block Pointer
  45. __STATIC_INLINE mem_block_t *MemBlockPtr (void *mem, uint32_t offset) {
  46.   uint32_t     addr;
  47.   mem_block_t *ptr;

  48.   //lint --e{923} --e{9078} "cast between pointer and unsigned int" [MISRA Note 8]
  49.   addr = (uint32_t)mem + offset;
  50.   ptr  = (mem_block_t *)addr;

  51.   return ptr;
  52. }


  53. //  ==== Library functions ====

  54. /// Initialize Memory Pool with variable block size.
  55. /// \param[in]  mem             pointer to memory pool.
  56. /// \param[in]  size            size of a memory pool in bytes.
  57. /// \return 1 - success, 0 - failure.
  58. __WEAK uint32_t osRtxMemoryInit (void *mem, uint32_t size) {
  59.   mem_head_t  *head;
  60.   mem_block_t *ptr;

  61.   // Check parameters
  62.   //lint -e{923} "cast from pointer to unsigned int" [MISRA Note 7]
  63.   if ((mem == NULL) || (((uint32_t)mem & 7U) != 0U) || ((size & 7U) != 0U) ||
  64.       (size < (sizeof(mem_head_t) + (2U*sizeof(mem_block_t))))) {
  65.     EvrRtxMemoryInit(mem, size, 0U);
  66.     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  67.     return 0U;
  68.   }

  69.   // Initialize memory pool header
  70.   head = MemHeadPtr(mem);
  71.   head->size = size;
  72.   head->used = sizeof(mem_head_t) + sizeof(mem_block_t);

  73.   // Initialize first and last block header
  74.   ptr = MemBlockPtr(mem, sizeof(mem_head_t));
  75.   ptr->next = MemBlockPtr(mem, size - sizeof(mem_block_t));
  76.   ptr->next->next = NULL;
  77.   ptr->next->info = sizeof(mem_head_t) + sizeof(mem_block_t);
  78.   ptr->info = 0U;

  79.   EvrRtxMemoryInit(mem, size, 1U);

  80.   return 1U;
  81. }

  82. /// Allocate a memory block from a Memory Pool.
  83. /// \param[in]  mem             pointer to memory pool.
  84. /// \param[in]  size            size of a memory block in bytes.
  85. /// \param[in]  type            memory block type: 0 - generic, 1 - control block
  86. /// \return allocated memory block or NULL in case of no memory is available.
  87. __WEAK void *osRtxMemoryAlloc (void *mem, uint32_t size, uint32_t type) {
  88.   mem_block_t *ptr;
  89.   mem_block_t *p, *p_new;
  90.   uint32_t     block_size;
  91.   uint32_t     hole_size;

  92.   // Check parameters
  93.   if ((mem == NULL) || (size == 0U) || ((type & ~MB_INFO_TYPE_MASK) != 0U)) {
  94.     EvrRtxMemoryAlloc(mem, size, type, NULL);
  95.     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  96.     return NULL;
  97.   }

  98.   // Add block header to size
  99.   block_size = size + sizeof(mem_block_t);
  100.   // Make sure that block is 8-byte aligned
  101.   block_size = (block_size + 7U) & ~((uint32_t)7U);

  102.   // Search for hole big enough
  103.   p = MemBlockPtr(mem, sizeof(mem_head_t));
  104.   for (;;) {
  105.     //lint -e{923} -e{9078} "cast from pointer to unsigned int"
  106.     hole_size  = (uint32_t)p->next - (uint32_t)p;
  107.     hole_size -= p->info & MB_INFO_LEN_MASK;
  108.     if (hole_size >= block_size) {
  109.       // Hole found
  110.       break;
  111.     }
  112.     p = p->next;
  113.     if (p->next == NULL) {
  114.       // Failed (end of list)
  115.       EvrRtxMemoryAlloc(mem, size, type, NULL);
  116.       //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  117.       return NULL;
  118.     }
  119.   }

  120.   // Update used memory
  121.   (MemHeadPtr(mem))->used += block_size;

  122.   // Update max used memory
  123.   p_new = MemBlockPtr(mem, (MemHeadPtr(mem))->size - sizeof(mem_block_t));
  124.   if (p_new->info < (MemHeadPtr(mem))->used) {
  125.     p_new->info = (MemHeadPtr(mem))->used;
  126.   }

  127.   // Allocate block
  128.   if (p->info == 0U) {
  129.     // No block allocated, set info of first element
  130.     p->info = block_size | type;
  131.     ptr = MemBlockPtr(p, sizeof(mem_block_t));
  132.   } else {
  133.     // Insert new element into the list
  134.     p_new = MemBlockPtr(p, p->info & MB_INFO_LEN_MASK);
  135.     p_new->next = p->next;
  136.     p_new->info = block_size | type;
  137.     p->next = p_new;
  138.     ptr = MemBlockPtr(p_new, sizeof(mem_block_t));
  139.   }

  140.   EvrRtxMemoryAlloc(mem, size, type, ptr);

  141.   return ptr;
  142. }

  143. /// Return an allocated memory block back to a Memory Pool.
  144. /// \param[in]  mem             pointer to memory pool.
  145. /// \param[in]  block           memory block to be returned to the memory pool.
  146. /// \return 1 - success, 0 - failure.
  147. __WEAK uint32_t osRtxMemoryFree (void *mem, void *block) {
  148.   const mem_block_t *ptr;
  149.         mem_block_t *p, *p_prev;

  150.   // Check parameters
  151.   if ((mem == NULL) || (block == NULL)) {
  152.     EvrRtxMemoryFree(mem, block, 0U);
  153.     //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  154.     return 0U;
  155.   }

  156.   // Memory block header
  157.   ptr = MemBlockPtr(block, 0U);
  158.   ptr--;

  159.   // Search for block header
  160.   p_prev = NULL;
  161.   p = MemBlockPtr(mem, sizeof(mem_head_t));
  162.   while (p != ptr) {
  163.     p_prev = p;
  164.     p = p->next;
  165.     if (p == NULL) {
  166.       // Not found
  167.       EvrRtxMemoryFree(mem, block, 0U);
  168.       //lint -e{904} "Return statement before end of function" [MISRA Note 1]
  169.       return 0U;
  170.     }
  171.   }

  172.   // Update used memory
  173.   (MemHeadPtr(mem))->used -= p->info & MB_INFO_LEN_MASK;

  174.   // Free block
  175.   if (p_prev == NULL) {
  176.     // Release first block, only set info to 0
  177.     p->info = 0U;
  178.   } else {
  179.     // Discard block from chained list
  180.     p_prev->next = p->next;
  181.   }

  182.   EvrRtxMemoryFree(mem, block, 1U);

  183.   return 1U;
  184. }
复制代码

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107463
QQ
 楼主| 发表于 2018-3-12 02:21:00 | 显示全部楼层
类似这种形式的:



/* 从内部SRAM分配100KB给动态内存使用 */        
os_init_mem(AppMalloc, 1024*80);

/* 将内部CCM SRAM的64KB全部供动态内存使用,用于JPEG软解 */
os_init_mem(AppMallocCCM, 1024*64);

/* 从SDRAM分配16MB给动态内存使用 */        
os_init_mem(AppMallocSDRAM, 1024*1024*16);

回复

使用道具 举报

44

主题

575

回帖

712

积分

金牌会员

积分
712
发表于 2018-3-12 08:05:23 | 显示全部楼层
好东西,
回复

使用道具 举报

2

主题

38

回帖

44

积分

新手上路

积分
44
发表于 2018-3-12 09:18:17 | 显示全部楼层
有没有内存使用率这些功能函数啊
回复

使用道具 举报

2

主题

36

回帖

153

积分

初级会员

积分
153
发表于 2018-3-12 10:25:42 | 显示全部楼层
我比较喜欢这种模式!!!
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107463
QQ
 楼主| 发表于 2018-3-12 10:35:28 | 显示全部楼层
smallmount 发表于 2018-3-12 09:18
有没有内存使用率这些功能函数啊

另一个rtx_mempool.c文件里面的支持。
回复

使用道具 举报

19

主题

326

回帖

383

积分

高级会员

积分
383
发表于 2018-3-12 10:39:09 | 显示全部楼层
在要求高可靠性的场合下,建议尽量不使用动态内存分配。特别是控制用途的一般情况需要可预见的结果,用动态内存后在很大的不可预见情况,导致安全性大大降低。
回复

使用道具 举报

6

主题

231

回帖

249

积分

高级会员

积分
249
发表于 2018-3-12 11:36:22 | 显示全部楼层
这个内存分配算法太差劲了,不值得使用。
第一、查找空块的算法效率低。
第二、不是最佳匹配,很容易造成碎片。
第三、侵入式分配,一旦内存越界使用会导致系统崩溃。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107463
QQ
 楼主| 发表于 2018-3-12 11:41:22 | 显示全部楼层
novice 发表于 2018-3-12 11:36
这个内存分配算法太差劲了,不值得使用。
第一、查找空块的算法效率低。
第二、不是最佳匹配,很容易造成 ...

非常感谢建议,实际测试效果还是很嗨的,搞搞MP3,JPEG,爽爽的。
回复

使用道具 举报

9

主题

161

回帖

188

积分

初级会员

积分
188
发表于 2018-3-12 19:56:16 | 显示全部楼层
novice 发表于 2018-3-12 11:36
这个内存分配算法太差劲了,不值得使用。
第一、查找空块的算法效率低。
第二、不是最佳匹配,很容易造成 ...

楼主有推介的么,我现在用的是FreeRTOS的heap4.c,感觉还可以
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107463
QQ
 楼主| 发表于 2018-3-13 16:49:13 | 显示全部楼层
RTX5的三种内存分配方式
QQ截图20180313164723.png
回复

使用道具 举报

7

主题

102

回帖

123

积分

初级会员

积分
123
发表于 2018-3-14 11:09:28 | 显示全部楼层
设计思想跟lwip等的类似,感觉上好像释放那里少了一点代码?如果当前释放的block前后都是空闲的时候,好像没合并后面那个block。
其实这种设计思想还是合适MCU这种东西的,没说的那么差,一般来说,MCU的RTOS的动态分配特性,就是短小精悍速度快,所以不用最佳匹配。至于内存越界,计算不是动态分配内存,静态的数组乱玩搞到内存越界也不奇怪。没MMU也不用MPU的话,跟这些算法没啥关系吧
回复

使用道具 举报

74

主题

1224

回帖

1446

积分

至尊会员

积分
1446
发表于 2020-3-28 23:19:48
eric2013 发表于 2018-3-12 02:21
类似这种形式的:

谢谢分享

6

主题

42

回帖

60

积分

初级会员

积分
60
发表于 2022-4-18 16:35:00 | 显示全部楼层
eric2013 发表于 2018-3-12 02:21
类似这种形式的:

AppMalloc 怎么定义啊?
是不是#define  APPMalloc  0x2000000  //=  MCU的内SRAM地址
#define  AppMallocSDRAM   0xC0000000
是这样的吗????
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107463
QQ
 楼主| 发表于 2022-4-19 09:32:32 | 显示全部楼层
中尴人 发表于 2022-4-18 16:35
AppMalloc 怎么定义啊?
是不是#define  APPMalloc  0x2000000  //=  MCU的内SRAM地址
#define  AppM ...

【STM32H743实验例程】实验8:STM32H743动态内存管理,同时分区管理AXI RAM,DTCM,SRAM1等五块空间
https://www.armbbs.cn/forum.php? ... 6087&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

4

主题

16

回帖

28

积分

新手上路

积分
28
发表于 2022-4-29 15:16:04 | 显示全部楼层
这种算法,时间就不可预测,没有ucos的好,但是请教一下ucos怎么预防内存被多次释放的问题
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107463
QQ
 楼主| 发表于 2022-5-3 08:36:30 | 显示全部楼层
alban 发表于 2022-4-29 15:16
这种算法,时间就不可预测,没有ucos的好,但是请教一下ucos怎么预防内存被多次释放的问题

uCOS的动态内存管理是数组块的分配和是释放,就是固定大小数组块列表,所以没有malloc之类的碎片问题。
回复

使用道具 举报

4

主题

16

回帖

28

积分

新手上路

积分
28
发表于 2022-6-23 07:21:37 | 显示全部楼层
eric2013 发表于 2022-5-3 08:36
uCOS的动态内存管理是数组块的分配和是释放,就是固定大小数组块列表,所以没有malloc之类的碎片问题。

大小是固定的,确实是,但是怎么预防内存被多次释放,没有看到保护
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-6-2 20:24 , Processed in 0.223600 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表