解决MQTT上报CJSON数据时频繁动态申请内存造成内存碎片问题

        在上报MQTT数据时,采用CJSON格式。由于每次上报数据都需执行CJSON格式转换,而此转换过程会涉及动态内存分配。如此一来,在上报MQTT消息时,便会导致内存频繁地进行动态申请与释放,进而产生内存碎片。
        为解决这一问题,我自定义了静态内存分配方式,并将其与CJSON标准库相结合。通过这种方式,成功解决了频繁动态申请内存的难题,有效避免了内存碎片的产生 。

        一般步骤是将CJSON对象使用cJSON_PrintUnformatted函数转换成普通字符串,然后封装到MQTT报文中,但是cJSON_PrintUnformatted函数中会多次调用malloc函数动态申请内存,如果每一次上报消息都要频繁申请内存,久而久之必定会产生大量内存碎片。

        静态内存分配是一种不错的解决方案

1.自定义内存分配函数

#include "cJSON.h"
#include "string.h"

static uint8_t mem_pool[2048];
static size_t mem_offset = 0;

void* custom_malloc(size_t size)
{

	if(mem_offset + size > 2048) 
		return NULL;

	void* ptr = &mem_pool[mem_offset];
	mem_offset += size;
    //printf("\r\n mem_offset:  %d\r\n",mem_offset);
	return ptr;
}

void custom_free(void* ptr)
{
	//静态内存无需释放,不执行任何操作
    //不能在该函数中修正offset偏移量,因为custom_malloc函数会在cJSON_PrintUnformatted中被连续多次调用
    //,因此offset修正因该在最后一次custom_malloc函数调用完毕执行,即在执行完cJSON_PrintUnformatted函数后再修正偏移量mem_offset
}

2.将自定义的内存分配函数使用CJSON标准库的钩子函数注册

//使用自定义的静态内存分配方法,防止在转换CJSON字符串时出现内存碎片问题
	cJSON_Hooks hooks = {.malloc_fn = custom_malloc,.free_fn = custom_free};
	cJSON_InitHooks(&hooks);

 3.定义偏移量修正函数

void reset_malloc(void)
{
    mem_offset = 0;
}

4.转换CJSON字符串,并封装到MQTT报文中

            xSemaphoreTake(xMutexPUBUF,portMAX_DELAY);               //保护PUB_BUF缓存区
            json_body = cJSON_PrintUnformatted(pOrder); 
            //json_body = cJSON_PrintBuffered(pOrder,1000,0);
            memset(PUB_BUF,0,PUBLISH_MAX_SIZE);
            memcpy(PUB_BUF,json_body,strlen(json_body));
            
            //静态分配的内存不需要释放,但是需要修正数组游标的偏移量,
            //当下一次转换字符串时,重新从静态数组第一位置开始存放数据
            reset_malloc();
            xSemaphoreGive(xMutexPUBUF);

5.在上报数据的任务中上报数据

		xSemaphoreTake(xMutexPUBUF,portMAX_DELAY);    				//抢占锁
		Mqtt_Publish(devPubTopic,PUB_BUF);
		xSemaphoreGive(xMutexPUBUF);  								//释放锁资源

6.使用FreeRTOS中的内存查询函数检查内存使用情况

printf("xPortGetFreeHeapSize = %d\r\n",xPortGetFreeHeapSize());
		printf("-X:run-B:block-R:ready-D:del-S:suspend-Heap mini %d-\r\n", xPortGetMinimumEverFreeHeapSize());
        vTaskDelay(1000);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值