Строковый массив не освобождается при выходе из области
Я использую серьезные утечки памяти в своем приложении, поэтому я настраиваю это чрезвычайно простое решение для проверки того, что происходит, когда массив String выходит из области видимости...
Я знаю, что в старой реализации String TextString отсутствовал деструктор, но эта текущая реализация, похоже, имеет его.
Я использую эту библиотеку MemoryFree (Обратите внимание, что этот связанный код теперь исправлен на основе принятого ответа на этот вопрос).
В коде рассматриваются два сценария: распределение массива char и строкового массива в двух разных функциях, чтобы принудительно закрыть область действия на обоих.
#include <MemoryFree.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
int freeBefore, freeAfter;
//TEST ALLOCATION OF CHAR ARRAY//
freeBefore = freeMemory();
AllocateCharArr();
freeAfter = freeMemory();
Serial.println("CHAR*: Before " + String(freeBefore)
+ ", After " + String(freeAfter)
+ ", Diff " + String(freeBefore - freeAfter));
//TEST ALLOCATION OF STRING//
freeBefore = freeMemory();
AllocateStringArr();
freeAfter = freeMemory();
Serial.println("STRING: Before " + String(freeBefore)
+ ", After " + String(freeAfter)
+ ", Diff " + String(freeBefore - freeAfter));
}
void AllocateCharArr() {
char s[100];
}
void AllocateStringArr() {
String s[100];
}
void loop() { /* empty */ }
Вывод:
CHAR *: До 1710 года, после 1710 года, Diff 0
STRING: до 1645, после 1309, Diff 336
Каким образом распределение массива String
не удаляется из памяти?
Ответы
Ответ 1
Я столкнулся с проблемами обработки памяти в версиях Arduino до 1.0 при тестировании класса String
(см. форум здесь).
Конструктор String использует realloc
внутренне, и это обработка (avr libc) динамической памяти, которая вызывает проблемы (из-за того, что указатель на вершину кучи __brkval
не обновляется после free()
).
Запустите следующий код, чтобы увидеть эти проблемы в версиях 0023, 0022 и т.д. В Arduino 1.0 код не должен содержать никаких утечек памяти:
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include <HardwareSerial.h>
#include <MemoryFree.h>
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
int freeBefore, freeAfter;
freeBefore = freeMemory();
void* buffer = malloc(10);
if (buffer == 0) {
Serial.println("Failed to allocate memory");
}
free(buffer);
freeAfter = freeMemory();
Serial.println("Before " + String(freeBefore)
+ ", After " + String(freeAfter)
+ ", Diff " + String(freeBefore - freeAfter));
}
void loop() {
}
Кроме того, библиотека MemoryFree, которую вы используете, может давать неправильные результаты, поскольку она не учитывает свободный список. Попробуйте обновленную версию MemoryFree.cpp
:
extern unsigned int __heap_start;
extern void *__brkval;
/*
* The free list structure as maintained by the
* avr-libc memory allocation routines.
*/
struct __freelist {
size_t sz;
struct __freelist *nx;
};
/* The head of the free list structure */
extern struct __freelist *__flp;
#include "MemoryFree.h";
/* Calculates the size of the free list */
int freeListSize() {
struct __freelist* current;
int total = 0;
for (current = __flp; current; current = current->nx) {
total += 2; /* Add two bytes for the memory block header */
total += (int) current->sz;
}
return total;
}
int freeMemory() {
int free_memory;
if ((int)__brkval == 0) {
free_memory = ((int)&free_memory) - ((int)&__heap_start);
} else {
free_memory = ((int)&free_memory) - ((int)__brkval);
free_memory += freeListSize();
}
return free_memory;
}
Ответ 2
Если вы просмотрите источник Arduino, вы можете столкнуться с файлом ".\arduino-1.0\hardware\arduino\cores\arduino\WString.cpp". В этом файле я заметил, что String не имеет конструктора по умолчанию (без параметров). Возможно, это может быть проблемой? Сомнительный, но в любом случае источник должен помочь. Удачи.
Ответ 3
Прокомментируйте строку String s[100];
и посмотрите, получаете ли вы разные результаты. Похоже, что выделение памяти, которое вы видите, связано с строковыми операциями в вашей функции setup()
, а не с объявлением локального массива строк в AllocateStrArr()
. Вы можете взглянуть на WString.cpp и WString.h, чтобы убедиться, что operator+
был переопределен, поэтому каждый вызов String()
или конкатенации с помощью +
может создать другой объект.