You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 23:21:25