使用cJSON数据格式向阿里云服务器发送数据,内存溢出问题解决方法
使用cJSON数据格式向阿里云物联网平台发送数据,内存溢出问题解决方法
- 一、问题提出
- 二、解决方法
- 1、参考cJSON_Data_Init()函数
- 2、增加vPortFree函数
- 3、分析原因
- 4、cJSON_free函数替换vPortFree函数
- 三、问题总结
一、问题提出
使用移植的FreeRTOS的STM32F407,借助4G DTU ,用RS485向阿里云物联网平台发送数据时,正常发送到阿里云几分钟后出现乱码,如图所示,代码如下。

static void DTU_Send_Task(void* parameter)
{uint8_t txbuf[100];char* p =NULL;while (1){TX_MODE(); //发送p = cJSON_Print(cJSON_Data);//将解析的字符串重新转化为文本格式,便于传输和存储memcpy(txbuf, p, 50);printf("%s",p);HAL_UART_Transmit(&huartx_RS485, (uint8_t*)txbuf, strlen((char*)txbuf), 1000);vTaskDelay(500); /* 延时500个tick */}
}
二、解决方法
1、参考cJSON_Data_Init()函数
如下的代码中,cJSON项目创建后,增加了一些键值对,定义的指针p指向cJSON_Print返回的指针所指向的地址,后又用vPortFree函数释放p所指向地址所存的数据。
cJSON* cJSON_Data_Init(void)
{cJSON* cJSON_Root = NULL; //json根节点cJSON_Root = cJSON_CreateObject(); /*创建项目*/if(NULL == cJSON_Root){return NULL;}/*---------------添加元素 键值对------------*/
// cJSON_AddStringToObject(cJSON_Root, NAME, DEFAULT_NAME); /*添加元素 键值对*/cJSON_AddNumberToObject(cJSON_Root, STATE, STATE_NUM); cJSON_AddNumberToObject(cJSON_Root, PRESSURE, PRESSURE_NUM);char* p = cJSON_Print(cJSON_Root); /*p 指向的字符串是json格式的,将解析的字符串重新转化为文本格式,便于传输和存储*/
// printf("%s\n",p);vPortFree(p);/*释放内存*/p = NULL;return cJSON_Root;
}
2、增加vPortFree函数
由上面的cJSON_Data_Init函数启发,在发送的Task中增加如下vPortFree函数释放p所指向地址所存的数据,代码如下:
static void DTU_Send_Task(void* parameter)
{ uint8_t txbuf[100];char* p =NULL;while (1){TX_MODE(); //发送p = cJSON_Print(cJSON_Data);//指针p指向cJSON_Print返回的指针所指向的地址,将解析的字符串重新转化为文本格式,便于传输和存储memcpy(txbuf, p, 50);printf("%s",p);HAL_UART_Transmit(&huartx_RS485, (uint8_t*)txbuf, strlen((char*)txbuf), 1000);vPortFree(p);/*释放内存*/p = NULL;vTaskDelay(500); /* 延时500个tick */}
}
等待几分钟,发送给阿里云的数据一直正常,如下图:

3、分析原因
在任务循环执行中,p指向cJSON_Print函数每次返回的指针所指向的地址,该地址包含新数据,那么旧数据会一直占用内存空间,直至内存堆栈溢出。查看vPortFree函数源码:
void vPortFree( void *pv )
{
uint8_t *puc = ( uint8_t * ) pv;
BlockLink_t *pxLink;if( pv != NULL ){/* The memory being freed will have an BlockLink_t structure immediatelybefore it. */puc -= xHeapStructSize;/* This casting is to keep the compiler from issuing warnings. */pxLink = ( void * ) puc;/* Check/// the block is actually allocated. */configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );configASSERT( pxLink->pxNextFreeBlock == NULL );if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 ){if( pxLink->pxNextFreeBlock == NULL ){/* The block is being returned to the heap - it is no longerallocated. */pxLink->xBlockSize &= ~xBlockAllocatedBit;vTaskSuspendAll();{/* Add this block to the list of free blocks. */xFreeBytesRemaining += pxLink->xBlockSize;traceFREE( pv, pxLink->xBlockSize );prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );}( void ) xTaskResumeAll();}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}
}/*----------上面函数中调用的prvInsertBlockIntoFreeList函数---------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t *pxBlockToInsert )
{
BlockLink_t *pxIterator;
uint8_t *puc;/* Iterate through the list until a block is found that has a higher addressthan the block being inserted. */for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock ){/* Nothing to do here, just iterate to the right position. */}/* Do the block being inserted, and the block it is being inserted aftermake a contiguous block of memory? */puc = ( uint8_t * ) pxIterator;if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert ){pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;pxBlockToInsert = pxIterator;}else{mtCOVERAGE_TEST_MARKER();}/* Do the block being inserted, and the block it is being inserted beforemake a contiguous block of memory? */puc = ( uint8_t * ) pxBlockToInsert;if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock ){if( pxIterator->pxNextFreeBlock != pxEnd ){/* Form one big block from the two blocks. */pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;}else{pxBlockToInsert->pxNextFreeBlock = pxEnd;}}else{pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;}/* If the block being inserted plugged a gab, so was merged with the blockbefore and the block after, then it's pxNextFreeBlock pointer will havealready been set, and should not be set here as that would make it pointto itself. */if( pxIterator != pxBlockToInsert ){pxIterator->pxNextFreeBlock = pxBlockToInsert;}else{mtCOVERAGE_TEST_MARKER();}
}
vPortFree函数主要是使用prvInsertBlockIntoFreeList( ) 函数 (如下代码),将原来创建的用于存放数据的链表块,插回到原链表中,即将分配过的内存放回去。
prvInsertBlockIntoFreeList( )函数 :首先遍历到目标链表的前一个链表块,判断后一个链表块的起始位置是否等于当前链表块+链表块的大小,即是否地址连续,若是,再将这两个链表合并,后面就是判断正在插入的块和它之前插入的块是否构成连续的内存块。
4、cJSON_free函数替换vPortFree函数
以上已经能够解决问题,但是vPortFree函数是FreeRTOS实时操作系统里面提供的释放内存函数,而经过查阅cJSON.h,cJSON提供了自己的释放内存函数:cJSON_free函数,那么同时将cJSON_Data_Init初始化函数与DTU_Send_Task任务函数里面的vPortFree函数替换成cJSON_free函数,长时间一直正常,未出现错误,如下代码:
cJSON* cJSON_Data_Init(void)
{cJSON* cJSON_Root = NULL; //json根节点cJSON_Root = cJSON_CreateObject(); /*创建项目*/if(NULL == cJSON_Root){return NULL;}/*---------------添加元素 键值对------------*/
// cJSON_AddStringToObject(cJSON_Root, NAME, DEFAULT_NAME); /*添加元素 键值对*/cJSON_AddNumberToObject(cJSON_Root, STATE, STATE_NUM); cJSON_AddNumberToObject(cJSON_Root, PRESSURE, PRESSURE_NUM);char* p = cJSON_Print(cJSON_Root); /*p 指向的字符串是json格式的,将解析的字符串重新转化为文本格式,便于传输和存储*/// printf("%s\n",p);cJSON_free(p);
// vPortFree(p);/*释放内存*/p = NULL;return cJSON_Root;
// cJSON_Delete(cJSON_Root);
// return p;
}static void DTU_Send_Task(void* parameter)
{ uint8_t txbuf[100];
// /* 使能接收中断 */
// __HAL_UART_ENABLE_IT(&huartx_RS485, UART_IT_RXNE);char* p =NULL;while (1){TX_MODE(); //发送p = cJSON_Print(cJSON_Data);//指针p指向cJSON_Print返回的指针所指向的地址,将解析的字符串重新转化为文本格式,便于传输和存储memcpy(txbuf, p, 50);printf("%s",p);HAL_UART_Transmit(&huartx_RS485, (uint8_t*)txbuf, strlen((char*)txbuf), 1000);cJSON_free(p);
// vPortFree(p);/*释放内存*/p = NULL;vTaskDelay(500); /* 延时500个tick */}
}
效果如下:

三、问题总结
出现内存溢出问题的根本是:FreeRTOS实时操作系统循环执行任务中,cJSON_Print函数所指向地址的旧数据一直未被释放导致,可以通过增加vPortFree函数或者cJSON_free函数来释放内存,解决该问题。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
