共计 2413 个字符,预计需要花费 7 分钟才能阅读完成。
我的项目场景:
之前为了不便 SDDC 协定应用,我本人写了一个 SDDC 的 SDK,具体详见:同人逼死官网系列!基于 sddc 协定的 SDK 框架 sddc_sdk_lib 解析 和 同人逼死官网系列 从 DDC 嗅探器到 sddc_sdk_lib 的数据解析,然而过后对 cjson 的应用还不是很相熟,导致呈现了一个内存泄露的问题,导致了 ESP32 运行一段时间后无奈收到报文。
问题形容
在频繁收到音讯命令,调用 sddc_on_message_lib 函数后,大略半小时左右 ESP32 将会收不到任何报文,通过打印发现 select 始终返回 0,这个问题一度让我十分费解。
网上最多的答复是 FD_SET 没有重置导致的,可是我查看了 sddc 代码,官网的确做了循环调用 FD_SET,没有问题,不是这个起因。
射频信号的确收回来了。
ESP32 底层也不应该有问题。
过后呈现问题的是一个 I2C 设施。导致我始终在狐疑是 I2C 导致的问题,别说还真有可能,ESP32 的 I2C 有可能会受到烦扰 I2C《调试教训分享》而后我苦兮兮的去检测 I2C,发现也是失常的。这就很令人费解了啊。
最初我无心中发现另外一个 通过 GPIO 读取数据的设施在长时间运行后也呈现这样的问题。我比照了这两个设施和其余没问题的设施,最初发现差别在触发 “get” 命令的频率上,而 “get” 是一个命令,会触发音讯解决回调函数,这样我才把注意力调到了回调解决流程上,而后发现了一处内存透露 ~□~||。
起因剖析:
内存泄露位于 SDDC_SDK_lib.c 中的 sddc_on_message_lib,外面调用的 cJSON_Parse 函数会在次级函数中申请内存给 root,须要手动开释一下。
(1)应用 root = cJSON_Parse(text); // 将文本转成 json 格局,次函数外面申请了一块内存给 root
所以在最初要开释 rootcJSON_Delete(root); // 开释 cJSON_Parse() 调配进去的内存空间
(2)应用 str =
cJSON_Print(root);// 次函数将 json 数据转成字符串,这个函数内申请了一段内存给 out,所以应用完 out 后也要开释(3)应用 cJSON *new_json_str =
cJSON_CreateString(str);// 将一个字符串转成一个 json 对象,函数外面也波及了内存调配,座椅用完当前也要开释 cJSON_Delete(new_json_str须要留神:cJSON_CreateObject 创立的指针,须要应用 cJSON_Delete 删除,cJSON_Print 赋值的指针须要 free 开释。对应不上是没方法真正开释的。
解决方案:
批改后的 sddc_on_message_lib 代码如下:其实就是在每一个出口处加了一个 cJSON_Delete(root); 函数开释内存。
static sddc_bool_t sddc_on_message_lib(sddc_t *sddc, const uint8_t *uid, const char *message, size_t len)
{cJSON *root = cJSON_Parse(message);
cJSON *Json_method;
uint8_t uimethod =DDC_METHOD_VALIDE;
Json_method = cJSON_GetObjectItem(root, "method");
if (NULL == Json_method) {cJSON_Delete(root);
return SDDC_FALSE;
}
if (cJSON_IsString(Json_method)) {if (strcmp(Json_method->valuestring,"set") == 0) {uimethod = DDC_METHOD_SET;} else if (strcmp(Json_method->valuestring,"get") == 0) {uimethod = DDC_METHOD_GET;} else {cJSON_Delete(root);
return SDDC_FALSE;
}
} else {cJSON_Delete(root);
return SDDC_FALSE;
}
if (uimethod == DDC_METHOD_VALIDE) {cJSON_Delete(root);
return SDDC_FALSE;
}
if (uimethod == DDC_METHOD_SET) {
int i;
/*
* 数字量、显示量先查问设置,避免开关量是设施的使能
*/
for (i=0; i<G_config->num_dev_reg_num; i++) {object_Number_Set(root, G_config->num_dev_reg[i].objname, G_config->num_dev_reg[i].Num_Fun);
}
for (i=0; i<G_config->dis_dev_num; i++) {object_Display_Set(root, G_config->dis_dev_reg[i].objname, G_config->dis_dev_reg[i].Dis_Fun);
}
for (i=0; i<G_config->io_dev_reg_num; i++) {object_IO_Set(root, G_config->io_dev_reg[i].objname, G_config->io_dev_reg[i].IO_Fun);
}
} else if (uimethod == DDC_METHOD_GET) {object_get(sddc, uid, root, G_config->state_get_reg, G_config->state_get_reg_num, 0);
} else {cJSON_Delete(root);
return SDDC_FALSE;
}
cJSON_Delete(root);
return SDDC_TRUE;
}