国内免费网站空间,电商系统app开发,公司核准名称网站,免费网站建设入门1.简介 多数传统的单片机并没有动态内存管理功能。单片机通常具有有限的存储资源#xff0c;包括固定大小的静态RAM#xff08;SRAM#xff09;用于数据存储和寄存器用于特定功能。这些资源在编译时被分配并且在程序的整个生命周期中保持不变。
2.动态内存管理好处 灵活性和…1.简介 多数传统的单片机并没有动态内存管理功能。单片机通常具有有限的存储资源包括固定大小的静态RAMSRAM用于数据存储和寄存器用于特定功能。这些资源在编译时被分配并且在程序的整个生命周期中保持不变。
2.动态内存管理好处 灵活性和效率动态内存管理可以根据程序的需要在运行时动态分配和释放内存空间。这种灵活性使得程序能够更高效地利用可用的内存资源避免了静态分配固定大小内存的限制。 节省内存空间动态内存管理允许程序只在需要时分配内存释放不再使用的内存。这样可以避免静态内存分配导致的内存浪费提高内存利用率。 支持动态数据结构许多数据结构如链表、树等大小在运行时无法预先确定需要动态分配内存以存储变量数量可变的元素。动态内存管理使得这些动态数据结构的实现变得简单和高效。 扩展性使用动态内存管理可以根据程序的需求动态地调整内存大小。这使得程序能够适应不同的输入规模和需求变化提供更好的扩展性和灵活性。
3.如何自行实现动态内存管理
3.1 步骤 分配内存空间首先需要实现一个分配内存空间的函数。该函数需要检查内存池中是否有足够的空闲内存。如果有空闲内存则将其标记为已使用并返回指向所分配内存块的指针。如果没有足够的空闲内存则需要采取相应的策略例如返回空指针或扩展内存池。 释放内存空间当不再需要分配的内存块时需要实现一个释放内存空间的函数。该函数需要接收指向待释放内存块的指针并将其标记为空闲状态以便后续的内存分配可以再次利用它。 管理内存池需要设计和管理一个内存池也称为内存堆。内存池是一个预先分配的内存区域用于存储动态分配和释放的内存块。需要跟踪每个已分配内存块的状态已使用或空闲以及其大小和地址信息。 错误处理和边界检查在实现动态内存管理时必须考虑各种错误情况和边界条件。例如分配失败、重复释放内存、越界访问等。需要在代码中加入相应的检查和错误处理机制以确保内存管理的正确性和安全性。 3.2方案 1.增加外部SRAM或者DRAM,使用外部空间来作为动态内存管理这种方法需要编写外部SRAM的驱动并将外部的SRAM地址映射到芯片地址中。 例如以下驱动控制器 STM32系列微控制器的FSMCFlexible Static Memory Controller是一种专门设计用于连接外部存储器设备如SRAM、NOR Flash等的控制器。 NXP LPC系列微控制器的EMCExternal Memory Controller来支持与外部存储器设备的数据交互可以连接多种类型的存储器如SRAM、NOR Flash、SDRAM等。 TM4C系列微控制器的嵌入式外部存储器接口EMIFA通过该接口可以连接外部存储器设备并支持SRAM、NOR Flash、NAND Flash等多种存储器类型。 2.使用内部SRAM的静态变量存储区来当作动态内存管理这部分空间不允许再当静态空间来操作这种方法无需依赖外部控制器但是同时也无法管理更大的动态空间。 4.实现 动态内存管理的本质就是对一段地址的管理。它涉及到在运行时动态分配和释放内存空间并管理各个内存块的状态可用性。
4.1直接使用静态变量
#define MEM_MAX_SIZE 100*1024 //100K
static unsigned char mem1base[MEM_MAX_SIZE]; //内部SRAM内存池
4.2使用外部SRAM地址需要映射
static unsigned char mem2base[MEM_MAX_SIZE] __attribute__((at(0XC0000000))); //外部SDRAM内存池
这里的地址0XC0000000只是示例 需要按照上文提到驱动控制器进行修改。
4.3 数据结构设计
typedef struct _MemBlockList
{union {struct {unsigned int valid : 1; // 0 表示未使用 1表示使用了unsigned int length : 31; // 长度};int info; // 整体的信息部分};struct _MemBlockList *next; // 下一块
} MemBlockList;//共占用8个字节typedef struct _MemoryManager
{void *start;void *end;unsigned int size;MemBlockList *head;
} MemoryManager;static MemoryManager g_memoryManager;
MemBlockList用于管理一块连续的内存区域并维护了一个内存块链表用于跟踪空闲和已分配的内存块MemoryManager用于表示内存管理器。通过使用这两个结构体可以实现对一块连续内存的管理包括内存块的分配和释放。g_memoryManager是一个全局的内存管理器变量用于在程序中跟踪和管理内存块的分配和释放情况。 4.4 动态内存的初始化
bool memoryManagerInit(void)
{int size MEM_MAX_SIZE;g_memoryManager.end memXbase size;g_memoryManager.start memXbase;g_memoryManager.size size;g_memoryManager.head (MemBlockList *)g_memoryManager.start;g_memoryManager.head-length g_memoryManager.size - sizeof(MemBlockList);g_memoryManager.head-valid 0;g_memoryManager.head-next NULL; printf(memoryManagerInit success : %d KB\n, size / 1024);return true;
}
4.6 动态内存的申请
void *memoryManager_malloc(int size)
{int free_size getMaxFreeBlockSize();if (free_size size){MemBlockList *ptr g_memoryManager.head;MemBlockList *free_block NULL;/* 指针对齐保证了 currentSize 是指针 sizeof(void*) 的整数倍大小 */int n size / sizeof(void*);int currentSize n * sizeof(void*);if (size % sizeof(void*) ! 0) {currentSize sizeof(void*);}bool isNeedCut false; //是否需要分割MemBlockList *node getFreeBlock(currentSize, isNeedCut); if (node NULL){printf(malloc size %d faile !!!!!\n, size);print_mem_info();return (void *)(NULL);}/* 标记内存块使用了 */node-valid 1;unsigned char *p (unsigned char *)node;if (isNeedCut){p sizeof(MemBlockList) currentSize;free_block (MemBlockList *)(p);free_block-length node-length - currentSize - sizeof(MemBlockList);free_block-valid 0;free_block-next node-next;node-next free_block;node-length currentSize;}p (unsigned char *)node;p sizeof(MemBlockList);//偏移8个字节为真正使用的malloc地址checkMem();print_mem_info();return (void *)(p);}return NULL;
} 首先通过调用getMaxFreeBlockSize函数获取当前可用的最大内存块的大小以判断是否能够满足请求的内存大小。 如果最大可用内存块的大小大于等于所需的内存大小size则尝试分配内存。 通过getFreeBlock函数查找一个合适大小的空闲内存块node并返回该内存块的指针。如果没有足够大的空闲内存块则打印错误消息并返回NULL。 将找到的内存块node标记为已使用valid 1。 计算实际分配的内存块大小currentSize并判断是否需要对内存块进行分割。 如果需要进行分割将原内存块的长度更新为currentSize并在其后创建一个新的空闲内存块free_block其长度为原内存块长度减去currentSize和sizeof(MemBlockList)的大小。 返回分配的内存块的起始地址即node指针偏移sizeof(MemBlockList)字节后的地址。
4.7 动态内存的释放
void memoryManager_free(void *ptr)
{if (ptr ! NULL){if ((ptr g_memoryManager.start) (ptr g_memoryManager.end)){/* 计算地址对应的原始节点 */MemBlockList *source_node (MemBlockList *)((unsigned char *)ptr - sizeof(MemBlockList));/* 找到node的前一个节点和下一个节点 */MemBlockList *previous_node g_memoryManager.head;while (previous_node previous_node-next ! source_node){previous_node previous_node-next;}MemBlockList *next_node source_node-next;checkMem();source_node-valid 0;MemBlockList *connect_node;if (previous_node (previous_node-valid 0))// 前一个节点是否空闲{connect_node source_node-next;int size source_node-length sizeof(MemBlockList);if (next_node (next_node-valid 0))// 下一个节点是否空闲{connect_node next_node-next;size next_node-length sizeof(MemBlockList);}previous_node-next connect_node;previous_node-length size;}else{connect_node source_node-next;int size source_node-length;if (next_node (next_node-valid 0)){ connect_node next_node-next;size next_node-length sizeof(MemBlockList);}source_node-next connect_node;source_node-length size;}checkMem();}else{printf(memoryManager_free not allowd this address %p(%p --- %p)\n, ptr, g_memoryManager.start, g_memoryManager.end);}}
}首先判断参数ptr是否为NULL如果是NULL则直接返回。 接下来检查ptr指向的内存地址是否在内存管理器所管理的内存范围内g_memoryManager.start到g_memoryManager.end之间。如果不在范围内则打印错误消息并返回。 计算ptr对应的原始内存节点source_node的地址即ptr指针向前偏移sizeof(MemBlockList)字节。 遍历内存块链表找到source_node的前一个节点previous_node和下一个节点next_node。 将source_node标记为未使用valid 0。 根据前一个节点previous_node和下一个节点next_node的状态进行内存块合并操作。 如果前一个节点previous_node存在且为空闲valid 0则将source_node与前一个节点连接并将原来的内存长度包括前一个节点的长度进行合并。 否则将source_node单独作为一个内存块且不与前一个节点连接。 最后调用checkMem函数检查内存状态。
5. 实现代码总览
#ifndef NULL
#define NULL ((void *)0)
#endiftypedef struct _MemBlockList
{union {struct {unsigned int valid : 1; // 0 表示未使用 1表示使用了unsigned int length : 31; // 长度};int info; // 整体的信息部分};struct _MemBlockList *next; // 下一块
} MemBlockList;//共占用8个字节typedef struct _MemoryManager
{void *start;void *end;unsigned int size;MemBlockList *head;
} MemoryManager;static MemoryManager g_memoryManager;/* 获取当前内存中空闲的最大块大小 */
static unsigned int getMaxFreeBlockSize(void)
{MemBlockList *node g_memoryManager.head;unsigned int size 0;while (node){if(node-valid 0){if (node-length size){size node-length;}}node node-next;}return size;
}/* 获取当前内存中 满足size条件下 最小的内存块 */
static MemBlockList *getFreeBlock(unsigned int size, bool *isNeedCutMem)
{MemBlockList *current_node g_memoryManager.head;MemBlockList *ret_node NULL;unsigned int min_size 0xffffffff;*isNeedCutMem false;while (current_node){if (current_node-valid 0 current_node-length size) //块是否空闲{bool current_cut false;if (current_node-length (size sizeof(MemBlockList) (sizeof(void *))))current_cut true;if (current_node-length min_size){min_size current_node-length;*isNeedCutMem current_cut;ret_node current_node;if (min_size size)break;}}current_node current_node-next;}return ret_node;
}/* 打印当前的内存使用情况 */
void print_mem_info(void)
{MemBlockList *node g_memoryManager.head;while (node){printf(address %p, valid %d, next %p, size %d\n, node, node-valid, node-next, node-length);node node-next;}
}/* 内存检查 */
static void checkMem(void)
{MemBlockList *node g_memoryManager.head;int size 0;int cnt 0;while (node){cnt ;size node-length;node node-next;}if (size (g_memoryManager.size - cnt * sizeof(MemBlockList))){printf(checkMem err now only have %d block, size %d!!!\n, cnt, size);print_mem_info();while (1);}return;
}/* 内存操作检查 */
static bool checkMemUse(void *ptr, int size)
{if((ptr g_memoryManager.start) || (ptr g_memoryManager.end)){//不在管控范围内的地址不进行校验return true;}MemBlockList *node g_memoryManager.head;unsigned char *current_p NULL;while (node){int current_size node-length;current_p (unsigned char *)node sizeof(MemBlockList);if ((ptr current_p) (ptr (current_p current_size))){if (node-valid 0){printf(checkMemUse this address %p is not active !!\n, ptr);return false;}else{if(size (node-length - ((unsigned char *)ptr - current_p))){printf(checkMemUse this address %p size %d, is size over, source address %p, len %d!!\n,ptr, size, current_p, node-length);return false;}}}node node-next;}return true;
} bool memoryManagerInit(void)
{int size MEM_MAX_SIZE;g_memoryManager.end memXbase size;g_memoryManager.start memXbase;g_memoryManager.size size;g_memoryManager.head (MemBlockList *)g_memoryManager.start;g_memoryManager.head-length g_memoryManager.size - sizeof(MemBlockList);g_memoryManager.head-valid 0;g_memoryManager.head-next NULL; printf(memoryManagerInit success : %d KB\n, size / 1024);return true;
}void *memoryManager_malloc(int size)
{int free_size getMaxFreeBlockSize();if (free_size size){MemBlockList *ptr g_memoryManager.head;MemBlockList *free_block NULL;/* 指针对齐保证了 currentSize 是指针 sizeof(void*) 的整数倍大小 */int n size / sizeof(void*);int currentSize n * sizeof(void*);if (size % sizeof(void*) ! 0) {currentSize sizeof(void*);}bool isNeedCut false; //是否需要分割MemBlockList *node getFreeBlock(currentSize, isNeedCut); if (node NULL){printf(malloc size %d faile !!!!!\n, size);print_mem_info();return (void *)(NULL);}/* 标记内存块使用了 */node-valid 1;unsigned char *p (unsigned char *)node;if (isNeedCut){p sizeof(MemBlockList) currentSize;free_block (MemBlockList *)(p);free_block-length node-length - currentSize - sizeof(MemBlockList);free_block-valid 0;free_block-next node-next;node-next free_block;node-length currentSize;}p (unsigned char *)node;p sizeof(MemBlockList);//偏移8个字节为真正使用的malloc地址checkMem();print_mem_info();return (void *)(p);}return NULL;
}void memoryManager_free(void *ptr)
{if (ptr ! NULL){if ((ptr g_memoryManager.start) (ptr g_memoryManager.end)){/* 计算地址对应的原始节点 */MemBlockList *source_node (MemBlockList *)((unsigned char *)ptr - sizeof(MemBlockList));/* 找到node的前一个节点和下一个节点 */MemBlockList *previous_node g_memoryManager.head;while (previous_node previous_node-next ! source_node){previous_node previous_node-next;}MemBlockList *next_node source_node-next;checkMem();source_node-valid 0;MemBlockList *connect_node;if (previous_node (previous_node-valid 0))// 前一个节点是否空闲{connect_node source_node-next;int size source_node-length sizeof(MemBlockList);if (next_node (next_node-valid 0))// 下一个节点是否空闲{connect_node next_node-next;size next_node-length sizeof(MemBlockList);}previous_node-next connect_node;previous_node-length size;}else{connect_node source_node-next;int size source_node-length;if (next_node (next_node-valid 0)){ connect_node next_node-next;size next_node-length sizeof(MemBlockList);}source_node-next connect_node;source_node-length size;}checkMem();}else{printf(memoryManager_free not allowd this address %p(%p --- %p)\n, ptr, g_memoryManager.start, g_memoryManager.end);}}
}void memoryManager_cpy(void *dest, const void *src, unsigned int n)
{if(checkMemUse(src, n) false){printf(memoryManager_cpy error check src\n);}if(checkMemUse(dest, n) false){printf(memoryManager_cpy error check dest\n);}for (unsigned int i 0; i n; i) {dest[i] src[i];}
}void memoryManager_set(void *ptr, unsigned char value, unsigned int num)
{if(checkMemUse(ptr, num) false){printf(memoryManager_set error check ptr\n);}for (unsigned int i 0; i num; i) {ptr[i] value;}
}