[1. Сохраняйте строки в памяти Flash]
(1) Разместите некоторые строки во flash, особенно длинные, такие как запросы HTML и шаблоны ответов. Например, строка изначально была определена так:
#define test_string "hello world"
Вы можете определить эту строку следующим способом, и тогда она будет размещена во flash:
static const char test_string[] ICACHE_RODATA_ATTR = "hello world";
(2) Когда определяете строковые константы с ICACHE_RODATA_ATTR, пользователи должны получать доступ к её содержимому операциями чтения, выровненными по размеру слова (байтовый адрес доступа должен нацело делиться на 4). Так как данные во flash должны быть прочитаны порциями по 4 байта, пользователи должны определить макрос для получения выровненной длины строки:
#define GET_ALIGN_STRING_LEN(str) ((strlen(str) + 3) & ~3)
Когда используются строки, выделите динамически новый объект массива, чтобы прочитать туда данные строки из flash. Затем используйте os_memcpy API для копирования содержимого строки:
unsigned int str_len = GET_ALIGN_STRING_LEN(test_string);
char *tmp_string = (char *)os_malloc(str_len);
os_memcpy(tmp_string, test_string, str_len);
(3) В коде приложения используйте test_string. Это также решит проблему исключений, вызванных приложениями при не выровненном доступе с содержимому памяти flash, одновременно снижая объем RAM, занимаемый Вашим приложением.
(4) Когда код пользователя использует метод получения данных, описанный выше, то нужно освобождать память с помощью вызова:
os_free(tmp_string);
Имейте в виду, что если этого не делать, то постоянные выделения памяти уменьшат её количество в куче, и для функционала ядра может не хватить памяти, что приведет к неправильной работе и отказу вызовов API.
[2. Сохраняйте данные констант во flash]
(1) Напрямую размещайте массивы unit32 в памяти flash. Пример:
const uint32 array[4] ICACHE_RODATA_ATTR =
{
0x11111111, 0x22222222, 0x33333333, 0x44444444
};
Пользователи могут напрямую использовать ячейки этого массива без каких-либо проблем (array[0], и т. п.).
(2) Однако доступы на чтение к массивам unit8 и unit16 должны быть выровнены по границе 4 байта. Пример:
const uint8 array[7] ICACHE_RODATA_ATTR = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
Если Вам нужно прочитать элементы в массиве char по байтам, попробуйте программно читать в память RAM элементы порциями по 4 байта, и затем читайте каждый байт по его смещению 0..3.. Прямой доступ к отдельным элементам байтового массива этого примера (array[1], и т. п.) приведет к отказу приложения.
(3) Для структур памяти общим принципом доступа к ним является выделение достаточного количества памяти в RAM, которое больше размера памяти структуры, которую Вы хотите прочитать. Читайте данные из порциями, размер которых делится на 4 байта, и сохраняйте их в RAM. Используйте указатель на объект в коде как обычно, что показано в предыдущем примере. Просто измените код для чтения структуры вместо чтения массива.
[3. Сохраняйте строки отладки в памяти flash]
Строки, выводимые на печать встроенной функцией printf, по умолчанию находятся в RAM. Если Вам не нужно часто печатать в лог строки отладки, или если эти строки слишком длинные, то используйте оптимизированное os_printf API для загрузки строк отладки во flash вместо RAM.
[4. Старайтесь избегать глобальных переменных]
Глобальные переменные часто занимают излишнее место, поскольку используются они скорее всего не во все время жизни приложения. Espressif предоставляет API для динамического выделения памяти, что можно применять для снижения использования глобальных переменных. Для программирования на основе событий всегда используйте os_malloc и os_free для динамического выделения места в памяти, когда это необходимо. Однако разработчики не рекомендуют использовать частое выделение/освобождение памяти порциями разного размера.