zoukankan      html  css  js  c++  java
  • 内存动态分配

    在单片机中由于内存资源紧张,不可能给每个任务分配专有的内存区,尤其是涉及到通讯模块的程序,对内存的使用更是敏感。为此开发一个简单的内存管理库,对以后的开发还是有着不小的帮助的。

    功能实现:内存动态分配、内存动态释放、内存碎片回收

    heap.c

    // 内存划分:申请的一块内存分为两部分,一部分用于存储链表结构体,另一部分给用户使用
    // 内存管理:链表不存在头节点和尾节点,理论上在内存在可以存在无数个节点,通过空闲标志位来识别该内存块是否可用
    #include "heap.h"
    #define HEAP_TRUE   1
    #define HEAP_FALSE   0
    #pragma pack(push, 1)
    typedef struct _sHeapList_t
    {
      unsigned int size; // 内存块大小
      unsigned char isfree; // 空闲标志
      unsigned char *penter; // 内存入口地址
      struct _sHeapList_t *plast; // 指向上一个节点,头节点为NULL
      struct _sHeapList_t *pnext; // 指向下一个节点,尾节点尾NULL
    }sHeapList_t;
    #pragma pack(pop)

    // 申请一个内存块,作为基础内存
    static unsigned char Heap[HEAP_TOTAL_SIZE];

    // 内存申请(注:函数不可重入)
    void *pmalloc(unsigned int size)
    {
      sHeapList_t *pnode = (sHeapList_t *)Heap;
      // 内存管理模块未初始化时需要执行初始化(以第一个节点是否存在作为判断依据)
      if(pnode->penter != (Heap + sizeof(sHeapList_t)))
      {
         pnode->plast = NULL;
         pnode->pnext = NULL;
         pnode->isfree = HEAP_TRUE;
         pnode->penter = Heap + sizeof(sHeapList_t); // 入口地址向后偏移一个结构体的位置
         pnode->size = HEAP_TOTAL_SIZE - sizeof(sHeapList_t); // 剩余内存需要减去一个结构体大小的空间
      }
      if(size > 0)
      {
        // 搜索一个不小于指定大小的内存块
        while(pnode != NULL)
        {
          if(pnode->isfree == HEAP_TRUE)
          {
            if(pnode->size >= size)
            {
              break;
            }
          }
          pnode = pnode->pnext;
        }
        // 找到了符合条件的内存块就进行分配,否则就直接返回NULL
        if(pnode != NULL)
        {
          // 找到的内存块大于所需内存,就需要进行拆分,因为每个内存块都需要一个内存管理结构体,所以
          // 如果拆分后另一个内存块大小大于一个结构体大小,则拆分出一个新的空闲内存块,并插入链表,
          // 如果拆分后另一个内存块大小小于一个结构体大小,无法作为一个新内存块使用,那就不拆分。
          if(pnode->size > (size + sizeof(sHeapList_t)))
          {
            unsigned char *start = pnode->penter + size;
            sHeapList_t *newnode = (sHeapList_t *)start;
            // 初始化新内存块
            newnode->plast = pnode;
            newnode->pnext = pnode->pnext;
            newnode->isfree = HEAP_TRUE;
            newnode->penter = start + sizeof(sHeapList_t);
            newnode->size = pnode->size - (size + sizeof(sHeapList_t));
            // 初始化用户申请的内存块
            pnode->size = size;
            pnode->pnext = newnode;
            pnode->isfree = HEAP_FALSE;
          }
          else
          {
            // 找到无法拆分的内存块就直接给用户使用
            pnode->isfree = HEAP_FALSE;
          }
          return pnode->penter; // 返回用户内存入口地址
        }
      }
      return NULL;
    }
    // 内存释放
    void pfree(void *p)
    {
      sHeapList_t *pnode = (sHeapList_t *)((unsigned char *)p - sizeof(sHeapList_t));
      if(pnode == NULL)
      {
        return;
      }
      // 因为内存块都是按地址顺序排列在链表中的(空闲内存块和用户内存块在同一个链表),
      // 因此释放时只需合并内存块就可以了
      if(pnode->pnext != NULL)
      {
        // 当下一个节点存在时,且是空闲内存块
        if(pnode->pnext->isfree == HEAP_TRUE)
        {
          // 当前节点和下一个节点相邻,可以合并
          pnode->size += pnode->pnext->size + sizeof(sHeapList_t);
          pnode->pnext = pnode->pnext->pnext;
        }
      }
      if(pnode->plast != NULL)
      {
        // 当上一个节点存在时,且是空闲内存块
        if(pnode->plast->isfree == HEAP_TRUE)
        {
          // 当前节点和上一个节点相邻,可以合并
          pnode->plast->size += pnode->size + sizeof(sHeapList_t);
          pnode->plast->pnext = pnode->pnext;
        }
      }
      pnode->isfree = HEAP_TRUE; // 不管内存块是否合并成功,最后都要将内存块设置为空闲状态
    }
     
    heap.h
    #ifndef __HEAP_H
    #define __HEAP_H
    // Define NULL pointer value
    #ifndef NULL
    #ifdef __cplusplus
    #define NULL 0
    #else
    #define NULL ((void *)0)
    #endif
    #endif
    // 模块功能:单片机内存动态管理,支持内存碎片回收
    // 动态管理的内存大小,单位:字节
    #define HEAP_TOTAL_SIZE (10 * 1024) // 10KB
    // 内存申请(注:函数不可重入)
    void *pmalloc(unsigned int size);
    // 内存释放(带有内存碎片回收机制)
    void pfree(void *p);
     
    #endif
     
  • 相关阅读:
    GARP和GVRP
    VLAN间路由
    Voice VLAN
    VLAN
    SSH
    Telnet
    FTP
    DHCP
    STP
    交换机
  • 原文地址:https://www.cnblogs.com/icode-wzc/p/12157504.html
Copyright © 2011-2022 走看看