超详细的嵌入式cJSON使用注意事项,持续补充中......

文章目录

  • 一、堆内存不足
    • [1.1 问题描述](#1.1 问题描述)
    • [1.2 解决办法](#1.2 解决办法)
  • 二、内存泄露
    • [2.1 忘记Delete](#2.1 忘记Delete)
    • [2.2 忘记Free](#2.2 忘记Free)
    • [2.3 串口数据接收缺少部分字符导致的内存泄露(自己的问题)](#2.3 串口数据接收缺少部分字符导致的内存泄露(自己的问题))
    • [2.4 内存泄露在Cortex-M3内核会发生什么?](#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()函数

使用示例

c 复制代码
root=cJSON_Parse(data);
if(root != NULL)
{
	/*
	对root进行进一步解析
	*/
	cJSON_Delete(root);	
}

2.2 忘记Free

在github主页可以看到这段话:使用cJSON_Print()这个函数打印json数据会申请一块内存,在使用完这个函数后你有义务释放掉这个函数所申请的内存

使用示例

c 复制代码
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造成的!惨痛的教训

*有问题的代码

c 复制代码
//==================================================================
//函 数 名: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格式化失败
    }
}

*修改后的代码

c 复制代码
//==================================================================
//函 数 名: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内核会发生什么?

未完待续...

相关推荐
jjyangyou38 分钟前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
xinghuitunan1 小时前
蓝桥杯顺子日期(填空题)
c语言·蓝桥杯
Half-up1 小时前
C语言心型代码解析
c语言·开发语言
懒大王就是我2 小时前
C语言网络编程 -- TCP/iP协议
c语言·网络·tcp/ip
半盏茶香2 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
小堇不是码农2 小时前
在VScode中配置C_C++环境
c语言·c++·vscode
小肥象不是小飞象2 小时前
(六千字心得笔记)零基础C语言入门第八课——函数(上)
c语言·开发语言·笔记·1024程序员节
励志成为嵌入式工程师7 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
Peter_chq7 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
hikktn9 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust