• contiki源码阅读之mmem.c


    上次我们说了list,这次我们就借着mmem.c的代码来用一下这个链表。

    代码目录是./core/lib/mmem.c

    结构体定义如下

    struct mmem {
      struct mmem *next;
      unsigned int size;
      void *ptr;
    };
    请注意,第一个成员必须是指针,这样才可以借用list的代码。

    第二个成员是要申请的字节数,第三个成员是指针,指向返回内存的首地址。

    插句话,对于单片机,如果想内存管理(不考虑虚拟地址,只考虑物理地址),主要有两种方法。一种是引出堆的指针,在此基础上自己封装,把这个堆管理起来(没有尝试过这种方法,也没有读到这方面的资料,留待以后研究。)还有一种方法,就是简单的定义一片全局变量,把这些空间管理起来。今天讨论的是第二种方法。

    #ifdef MMEM_CONF_SIZE
    #define MMEM_SIZE MMEM_CONF_SIZE
    #else
    #define MMEM_SIZE 4096
    #endif
    
    LIST(mmemlist);
    unsigned int avail_memory;
    static char memory[MMEM_SIZE];

    这里定义了全局数组,4096个字节。

    定义了全局变量avail_memory,用来记录还剩余多少个字节没有分配。

    定义了一个链表(上次已经介绍过相关代码了)。


    void
    mmem_init(void)
    {
      list_init(mmemlist);
      avail_memory = MMEM_SIZE;
    }

    初始化函数,初始化链表并且设置全局变量avail_memory=4096,4K个字节。

    在上次的list.h文件中,可以看到作者这样的注释:

    A linked list is made up of elements where the first element  must be a pointer. This pointer is used by the linked list library to form lists of the elements.

    这呼应了开头的话,因为list里面就是一个指针,所以用户的结构体必须把指针作为第一个成员,这样才能在不同指针(用户的结构体和 struct list)之间自由转换而不会发生错位。


    int
    mmem_alloc(struct mmem *m, unsigned int size)
    {
      /* Check if we have enough memory left for this allocation. */
      if(avail_memory < size) {
        return 0;
      }
    
      /* We had enough memory so we add this memory block to the end of
         the list of allocated memory blocks. */
      list_add(mmemlist, m);
    
      /* Set up the pointer so that it points to the first available byte
         in the memory block. */
      m->ptr = &memory[MMEM_SIZE - avail_memory];//这句赋值,把那段全局数组和m里面的指针联系起来了,有了m,就能找到那片内存
    
      /* Remember the size of this memory block. */
      m->size = size;
    
      /* Decrease the amount of available memory. */
      avail_memory -= size;
    
      /* Return non-zero to indicate that we were able to allocate
         memory. */
      return 1;
    }
    这就是内存分配函数。


    void
    mmem_free(struct mmem *m)
    {
      struct mmem *n;
    
      if(m->next != NULL) {
        /* Compact the memory after the allocation that is to be removed
           by moving it downwards. */
        memmove(m->ptr, m->next->ptr,
    	    &memory[MMEM_SIZE - avail_memory] - (char *)m->next->ptr);
        
        /* Update all the memory pointers that points to memory that is
           after the allocation that is to be removed. */
        for(n = m->next; n != NULL; n = n->next) {
          n->ptr = (void *)((char *)n->ptr - m->size);
        }
      }
    
      avail_memory += m->size;
    
      /* Remove the memory block from the list. */
      list_remove(mmemlist, m);
    }
    内存的释放。首先看看要释放的是不是链表的最后一个元素,如果是,那么就简单了,把字节数还回去,再把这块内存从链表上脱离。

    如果不是,就要进行字节的拷贝。把这个内存之后的所有内容(内存的末尾减去后面的内存块的起始地址)向前面移动(移动的距离刚好是这个内存块的大小)。

    但是这样还没有完,因为后面的内存块移动了,所以要修改每个内存块的指针,指针的值也要相应减少m->size个字节。

    这样做的好处是什么,就是没有内存碎片。因为每次释放,都会把后面的内容移动到前面,填补释放的空洞。




  • 相关阅读:
    【3.5】类和实例属性的查找顺序--mro查找
    【3.4】类变量和实例变量
    【3.3】isinstance和type的区别
    【3.2】抽象基类(abc模块)
    【3.1】鸭子类型和多态
    学习笔记 | 浅谈虚拟函数(Virtual Function)
    学习笔记 | Udacity CarND Term 1: Computer Vision and Deep Learning
    命令行 | File Compression in Linux
    Python: if else in a list comprehension
    Topic | Hyperparameter Optimization for Neural Networks
  • 原文地址:https://www.cnblogs.com/longintchar/p/5224438.html
Copyright © 2020-2023  润新知