有没有办法处理 AVR/Arduino 微控制器中的堆内存碎片?
Is there a way to handle heap memory fragmentation in AVR/Arduino microcontrollers?
我已经搜索了几天了,没有任何运气。
堆内存碎片是在 microcontrollers/Arduino 中大量使用 malloc() 和 free() 的结果。
如果不可避免地要使用它们,我如何不时地对堆进行碎片整理以确保下一次 malloc() 调用会找到连续的内存来分配?
创建一个固定大小的内存块池。当您需要任何数量的内存时,从池中分配一个块并使用您需要的部分。完成后,return 将块放入池中。池永远不会碎片化,因为块的大小总是相同的。如果有任何块可用,那么它们的大小总是合适的。有时您只需要几个字节,有那么一瞬间您会认为占用整个块是一种浪费。但是你会记得你正在避免内存碎片,你会感觉更好。
如果分配的大小变化很大,那么一个固定大小的内存池可能真的太浪费了。然后你可以为小型、中型和大型块制作两个或三个固定大小的内存池。但是请确保您 return 将块放入您从中获取它们的同一池中。
使用队列或链表来组织池中的块。块在分配时从 queue/list 中删除。当他们被释放时,他们会 return 进入 queue/list。
如@kkrambo 所述,使用队列或链表来跟踪分配的内存块。我已经包含了一个专门针对 Arduino 的示例,它没有我想要的所有功能。
我选择只保留指向队列中内存块的指针,而不是内存块本身(这似乎是 kkrambo 所说的,尽管我不知道 s/he 是否意味着我上面所说的。 )
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);
}
我已经搜索了几天了,没有任何运气。
堆内存碎片是在 microcontrollers/Arduino 中大量使用 malloc() 和 free() 的结果。
如果不可避免地要使用它们,我如何不时地对堆进行碎片整理以确保下一次 malloc() 调用会找到连续的内存来分配?
创建一个固定大小的内存块池。当您需要任何数量的内存时,从池中分配一个块并使用您需要的部分。完成后,return 将块放入池中。池永远不会碎片化,因为块的大小总是相同的。如果有任何块可用,那么它们的大小总是合适的。有时您只需要几个字节,有那么一瞬间您会认为占用整个块是一种浪费。但是你会记得你正在避免内存碎片,你会感觉更好。
如果分配的大小变化很大,那么一个固定大小的内存池可能真的太浪费了。然后你可以为小型、中型和大型块制作两个或三个固定大小的内存池。但是请确保您 return 将块放入您从中获取它们的同一池中。
使用队列或链表来组织池中的块。块在分配时从 queue/list 中删除。当他们被释放时,他们会 return 进入 queue/list。
如@kkrambo 所述,使用队列或链表来跟踪分配的内存块。我已经包含了一个专门针对 Arduino 的示例,它没有我想要的所有功能。 我选择只保留指向队列中内存块的指针,而不是内存块本身(这似乎是 kkrambo 所说的,尽管我不知道 s/he 是否意味着我上面所说的。 )
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);
}