文章目录
- 一、堆内存不足
- 1.1 问题描述
- 1.2 解决办法
- 二、内存泄露
- 2.1 忘记Delete
- 2.2 忘记Free
- 2.3 串口数据接收缺少部分字符导致的内存泄露(自己的问题)
- 问题分析
- 2.4 内存泄露在Cortex-M3内核会发生什么?
cJSON开源库地址: cJSON
一、堆内存不足
1.1 问题描述
这是大家遇到最多的问题之一,在Keil5中给STM32F103ZET6默认分配的堆大小是0x200,在数据量比较大的时候容易出现内存溢出错误。如果数据量不大,那么无所谓,但是数据量大了就到出现堆内存爆满。
1.2 解决办法
修改堆大小,找到.s文件,再找到堆大小,将0x200修改为0xf00,这个数根据需求定。
二、内存泄露
2.1 忘记Delete
在使用cJSON_Parse()函数解析json数据后,我们需要释放掉这个函数所申请的内存,因为设计到json嵌套的问题,所以需要使用cJSON库中的释放函数cJSON_Delete()函数
使用示例
root=cJSON_Parse(data);
if(root != NULL)
{/*对root进行进一步解析*/cJSON_Delete(root);
}
2.2 忘记Free
在github主页可以看到这段话:使用cJSON_Print()这个函数打印json数据会申请一块内存,在使用完这个函数后你有义务释放掉这个函数所申请的内存。
使用示例
char *json_string = cJSON_Print(item);
if (json_string)
{printf("%s\n", json_string);free(json_string);//1.5版本以上也可以使用以下函数进行释放//cJSON_free(json_string);}
2.3 串口数据接收缺少部分字符导致的内存泄露(自己的问题)
由于return造成的!惨痛的教训
*有问题的代码
//==================================================================
//函 数 名:pid_parameter_change
//功 能:接收字符串格式化为JSON格式,解析其中pid数据,并修改对应pid结构体
//输入参数:字符串指针,pid结构体指针
//返 回 值:0表示解析成功,1表示解析错误
//==================================================================
uint8_t pid_parameter_change(const char *data,PID *pid)
{cJSON *root=NULL;cJSON *kp=NULL,*ki=NULL,*kd=NULL;float p,i,d;root=cJSON_Parse(data);if(root!=NULL){/* 解析Kp */kp=cJSON_GetObjectItem(root,"kp");if(kp == NULL) return 1;else p=cJSON_GetNumberValue(kp);/* 解析Ki */ki=cJSON_GetObjectItem(root,"ki");if(ki == NULL) return 1;else i=cJSON_GetNumberValue(ki);/* 解析Kd */kd=cJSON_GetObjectItem(root,"kd");if(kd == NULL) return 1;else d=cJSON_GetNumberValue(kd);/* 修改PID参数 */pid->Kp=p;pid->Ki=i;pid->Kd=d;printf("%p\r\n",root);cJSON_Delete(root);root=NULL,kp=NULL,ki=NULL,kd=NULL;return 0;}else{cJSON_Delete(root);root=NULL;return 1; //root数据JSON格式化失败}
}
*修改后的代码
//==================================================================
//函 数 名:pid_parameter_change
//功 能:接收字符串格式化为JSON格式,解析其中pid数据,并修改对应pid结构体
//输入参数:字符串指针,pid结构体指针
//返 回 值:0表示解析成功,1表示解析错误
//==================================================================
uint8_t pid_parameter_change(const char *data,PID *pid)
{cJSON *root=NULL;cJSON *kp=NULL,*ki=NULL,*kd=NULL;float p,i,d;if(data[0] == '{' && data[UART1_Rx_cnt-3] == '}' ){root=cJSON_Parse(data);if(root){/* 解析Kp */kp=cJSON_GetObjectItem(root,"kp");if(kp == NULL) { cJSON_Delete(root);return 1;}else p=cJSON_GetNumberValue(kp);/* 解析Ki */ki=cJSON_GetObjectItem(root,"ki");if(ki == NULL) { cJSON_Delete(root);return 1;}else i=cJSON_GetNumberValue(ki);/* 解析Kd */kd=cJSON_GetObjectItem(root,"kd");if(kd == NULL) { cJSON_Delete(root);return 1;}else d=cJSON_GetNumberValue(kd);/* 修改PID参数 */pid->Kp=p;pid->Ki=i;pid->Kd=d;/*删除JSON,否则可能会发送内存泄露*/cJSON_Delete(root);root=NULL,kp=NULL,ki=NULL,kd=NULL; // 释放掉的内存指向NULL,避免产生野指针return 0;}else{/*删除JSON,否则可能会发送内存泄露*/cJSON_Delete(root);root=NULL;return 1; //root数据JSON格式化失败} }else{return 1;}
}
问题分析
这个问题的根源是由于串口接收到的数据不全导致的!同时也有我代码不严谨的问题。
在有问题的那个代码中,使用cJSON_Parse()成功解析出数据,使得代码进入了if语句中 , if(root)
进入if语句后,再次判断json对象是否有ki这个元素
这个时候出现了问题,由于串口接收缺少了ki中的i这个字符,使得if语句判断结果未false,直接return了。 if(ki == NULL) .
注意,return之前我没有使用cJSON_Delete()删除root,所以出现了内存泄露!
写代码的时候没考虑到cJSON_Parse()成功后,解析不出json对象中的元素的问题!
2.4 内存泄露在Cortex-M3内核会发生什么?
未完待续…