有没有办法处理 AVR/Arduino 微控制器中的堆内存碎片?

Posted

技术标签:

【中文标题】有没有办法处理 AVR/Arduino 微控制器中的堆内存碎片?【英文标题】:Is there a way to handle heap memory fragmentation in AVR/Arduino microcontrollers? 【发布时间】:2015-03-28 21:16:39 【问题描述】:

我已经找了几天了,没有任何运气。

堆内存碎片是在微控制器/Arduino 中大量使用 malloc() 和 free() 的结果。

如果使用它们是不可避免的,我如何不时对堆进行碎片整理以确保下一次 malloc() 调用会找到要分配的连续内存?

【问题讨论】:

您可以修改 malloc 以便它返回块的句柄,然后在每次需要访问块时将句柄转换为实际指针的函数。这样,您可以滚动自己的碎片整理,定期重新排列内存并更新句柄表。 有趣,你有示例代码吗?或者你能指出我的方向吗? 【参考方案1】:

创建一个固定大小的内存块池。当您需要任何数量的内存时,从池中分配一个块并使用您需要的部分。完成后,将块返回到池中。池永远不会碎片,因为块总是相同的大小。如果有任何块可用,那么它们的大小总是正确的。有时你只需要几个字节,然后你会认为你浪费了整个块。但是你会记得你正在避免内存碎片,你会感觉更好。

如果您的分配大小差异很大,那么一个固定大小的内存池可能真的太浪费了。然后,您可以为小型、中型和大型块创建两个或三个固定大小的内存池。但请确保将块返回到您从中获取它们的同一池中。

使用队列或链表来组织池中的块。这些块在分配时从队列/列表中删除。当它们被释放时,它们会返回到队列/列表中。

【讨论】:

但是如果使用 malloc() 是不可避免的,有什么办法可以对内存进行碎片整理? 重置设备并重新初始化堆将会对内存进行碎片整理。可能会在 malloc() 失败时重置,或者定期重置,或者当您的应用程序处于方便状态时重置。 但这和对内存进行碎片整理不一样,会丢弃所有分配的数据。【参考方案2】:

正如@kkrambo 提到的,使用队列或链表来跟踪分配的内存块。我已经包含了一个专门针对 Arduino 的示例,它没有我想要的所有花里胡哨。 我选择只保留指向队列中内存块的指针,而不是块本身(这似乎是 kkrambo 所说的,尽管我不知道他/她是否是我上面所说的意思。)

const int MAX_POOL_SIZE = 4;
const int MAX_DATA_SIZE = 128;

// Memory pool for data
QueueArray <uint8_t*> dataPool;

void initDataPool () 
  uint8_t * ptr;
  for (int i = 0; i < MAX_POOL_SIZE; i++) 
    ptr = (uint8_t*) malloc(MAX_DATA_SIZE);     // Allocate MAX_DATA_SIZE buffer
    dataPool.push(ptr);                         // Push buffer pointer to queue
  


// Allocate message data buffer from data pool
// If data pool still has buffer space available, and requested
// buffer size is suitable, return pointer to avalable buffer
static void* allocateDataBuff (size_t buffSize) 
  if (!dataPool.isEmpty()) 
    if (buffSize < MAX_DATA_SIZE) return dataPool.pop();
    else 
      if (debugMsg) Serial.println("allocateDataBuff: Requested Buffer Size is too large");
      return NULL;
    
   // if message pool still has buffer space available
  else 
    if (debugMsg) Serial.println("allocateDataBuff: Memory pool is full, no buffers available at this time");  
  

void setup() 
    initDataPool();

void loop() 
    // ........
    uint8_t* dataPtr = (uint8_t*) allocateDataBuff(100);
    // ....assign message to *dataPtr
    // ........
    deallocateDataBuff(dataPtr);

【讨论】:

以上是关于有没有办法处理 AVR/Arduino 微控制器中的堆内存碎片?的主要内容,如果未能解决你的问题,请参考以下文章

深入浅出处理器(上)

AVR/Arduino:读取定时器切换端口引脚

VHDL微处理器/微控制器

将人工智能模型压缩到微控制器中

微控制器的虚拟化

STM32F103C8T6微控制器 功能怎么样? 这个型号芯片解密成功率高吗?