ESP32用ArduinoJson序列化JSON触发栈溢出保护故障求助
ESP32 ArduinoJson序列化时栈溢出错误解决方案
问题现象
- 使用ArduinoJson库序列化JSON时,ESP32触发
Stack smashing protect failure!错误并重启 - 解码后的堆栈跟踪如下:
0x40083d51: panic_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/panic.c:408 0x4008cecd: esp_system_abort at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/esp_system.c:137 0x400831d6: __stack_chk_fail at /Users/ficeto/Desktop/ESP32/ESP32S2/esp-idf-public/components/esp_system/stack_check.c:35 0x400e35d5: makeStructJsonString(SensorMsg) at Handlers/TasksHandler.h:1206 0x400e395b: __networkHandler(void*) at src/RTOSHandler.cpp:757
- 错误指向
makeStructJsonString函数第1206行的String jsonString_;声明 - 已将任务栈从15KB提升至20KB,问题仍未解决
解决方案
1. 避免在栈上创建大对象
ArduinoJson默认内存分配和String对象都会占用栈空间,JSON数据较大时易触发溢出:
- 使用
DynamicJsonDocument时,改用堆内存分配并序列化到堆缓冲区:DynamicJsonDocument doc(2048); // 填充JSON数据 doc["sensor"] = "temperature"; doc["value"] = 25.5; size_t jsonLen = measureJson(doc); char* jsonBuffer = (char*)malloc(jsonLen + 1); if (jsonBuffer != NULL) { serializeJson(doc, jsonBuffer, jsonLen + 1); // 使用jsonBuffer处理数据 free(jsonBuffer); // 使用后释放内存 } - 替换栈上
String为堆分配的字符数组,减少栈占用。
2. 传递结构体指针而非值
若SensorMsg是较大结构体,按值传递会在栈上拷贝整个结构体,大幅增加栈负载:
- 修改函数声明为指针传递:
// 原函数:String makeStructJsonString(SensorMsg msg); // 修改为:String makeStructJsonString(const SensorMsg* msg); - 调用时传递结构体地址:
SensorMsg sensorData; // 填充sensorData makeStructJsonString(&sensorData);
3. 检查任务栈实际占用
用ESP-IDF自带函数查看任务剩余栈空间,确认栈大小是否足够:
void __networkHandler(void* param) { while(1) { // 定期打印剩余栈空间 Serial.printf("Network task remaining stack: %u bytes\n", uxTaskGetStackHighWaterMark(NULL)); // 其他任务逻辑 vTaskDelay(pdMS_TO_TICKS(1000)); } }
若剩余栈持续低于几百字节,需继续增大栈或优化其他栈上对象。
4. 直接序列化到输出流
跳过中间字符串存储,直接将JSON序列化到目标输出(如网络客户端、串口),完全避免内存占用:
DynamicJsonDocument doc(1024); // 填充JSON数据 doc["id"] = 1; doc["status"] = "ok"; // 直接序列化到网络客户端 serializeJson(doc, client); // 或直接输出到串口 serializeJson(doc, Serial);
5. 临时关闭栈保护(不推荐)
若以上方法均无效,可临时关闭栈保护用于调试,但会降低系统稳定性:
- 在ESP-IDF编译配置中关闭
CONFIG_STACK_CHECK选项; - 或在Arduino IDE中修改平台配置文件,禁用栈保护。
内容的提问来源于stack exchange,提问作者Majid Dareini
相关产品推荐
相关产品推荐

