cJSON内存释放记录

记录一下使用cjson库遇到的内存问题。

这个两位博主分析得很好,特此感谢。

参考博客:

cjson内存泄漏问题注意事项_u013564851的博客-优快云博客_cjson内存泄漏

C语言 cJSON cJSON_Delete 与 cJSON_Free 的区别、如何释放内存、调试内存泄漏方法_kiraskyler的博客-优快云博客

记录

        cjson创建节点的时候会动态分配内存,使用完后需要及时释放,否则会因内存不足申请失败,发段错误的情况出现。

        在释放内存的时候需要注意,cJSON提供了两个释放函数,分别用于释放不同的分配情况。

<think> 我们之前讨论过cJSON库,但未涉及静态内存分配。用户当前明确询问cJSON库中静态分配内存的使用方法。 在cJSON库中,通常使用动态内存分配(如malloc、free),但用户希望使用静态分配(即预先分配固定大小的内存,避免动态分配)。 查阅cJSON库的文档和源码,可以知道: 1. cJSON本身在创建对象(如cJSON_CreateObject等)时会动态分配内存。 2. 为了支持静态内存分配,cJSON提供了一个替代方案:使用`cJSON_InitHooks`函数来设置自定义的内存分配函数。 3. 但是,更直接的方法是使用cJSON库的“无内存分配”模式,这需要用户自己管理内存,通常通过预先分配一个足够大的内存池,并重写内存分配函数。 具体步骤: a. 定义一个静态内存池(例如一个全局的字符数组)。 b. 实现自定义的malloc和free函数,从静态内存池中分配和释放(注意:静态分配通常不释放,或者循环使用)。 c. 在程序初始化时,通过`cJSON_InitHooks`将自定义的内存分配函数设置给cJSON。 另外,cJSON库还提供了另一种方式:使用`cJSON_ParseWithOpts`并传递一个预分配的缓冲区,但这种方式需要结合自定义的内存钩子(hooks)。 详细说明: 1. 定义内存池和分配管理: 我们需要一个静态数组作为内存池,并维护一个指针来记录当前分配的位置(简单起见,可以只分配不释放,或者重置整个池)。 2. 实现自定义的内存分配和释放函数: 例如: ```c static char memory_pool[4096]; // 假设4KB的静态内存池 static size_t pool_index = 0; void *custom_malloc(size_t size) { if (pool_index + size > sizeof(memory_pool)) { return NULL; // 内存不足 } void *ptr = &memory_pool[pool_index]; pool_index += size; return ptr; } void custom_free(void *ptr) { // 静态分配通常不释放,或者我们只允许重置整个池 // 所以这里什么都不做,或者可以记录需要释放内存,但简单场景下忽略 } ``` 3. 初始化cJSON内存钩子: 在程序开始时(在任何cJSON调用之前): ```c cJSON_Hooks hooks; hooks.malloc_fn = custom_malloc; hooks.free_fn = custom_free; cJSON_InitHooks(&hooks); ``` 4. 之后,所有cJSON内存分配都将使用我们的自定义函数。 注意事项: - 这种方法下,内存池大小固定,如果解析的JSON对象太大导致内存池耗尽,则会失败。 - 由于静态内存分配不会释放,所以适合一次性使用或定期重置整个内存池(将pool_index置0)的场景。 另外,cJSON库在解析JSON字符串时,会先分配一个cJSON对象树(包括各种cJSON结构体和字符串等)。因此,内存池的大小需要根据预期的JSON结构来估算。 示例代码: 下面是一个完整的示例,展示如何使用静态内存池解析一个JSON字符串: ```c #include <stdio.h> #include "cJSON.h" // 定义静态内存池 #define MEMORY_POOL_SIZE 4096 static char memory_pool[MEMORY_POOL_SIZE]; static size_t pool_index = 0; void *custom_malloc(size_t size) { if (pool_index + size > MEMORY_POOL_SIZE) { return NULL; } void *ptr = (void*)&memory_pool[pool_index]; pool_index += size; return ptr; } void custom_free(void *ptr) { // 不做操作 } int main() { // 初始化cJSON内存钩子 cJSON_Hooks hooks; hooks.malloc_fn = custom_malloc; hooks.free_fn = custom_free; cJSON_InitHooks(&hooks); // 重置内存池索引(如果需要重复使用,可以在每次解析前重置) pool_index = 0; const char *json_string = "{\"name\":\"Alice\",\"age\":25}"; cJSON *root = cJSON_Parse(json_string); if (root == NULL) { printf("解析失败\n"); return -1; } // 使用cJSON对象... cJSON *name = cJSON_GetObjectItem(root, "name"); if (cJSON_IsString(name)) { printf("name: %s\n", name->valuestring); } cJSON *age = cJSON_GetObjectItem(root, "age"); if (cJSON_IsNumber(age)) { printf("age: %d\n", age->valueint); } // 注意:这里我们不再需要释放root,因为custom_free什么都不做 // 但如果我们想重置内存池以便下一次解析,可以简单地将pool_index置0 // 但是要注意,重置后之前的数据将失效,而且不能在多次解析之间使用多个cJSON树(除非一次解析完成后再重置) // 重置内存池(准备下一次解析) pool_index = 0; return 0; } ``` 注意:在实际应用中,需要确保在一次解析过程中不会超出内存池大小,并且根据场景决定是否重置内存池。 如果用户希望在嵌入式系统等资源受限环境中使用,这种方法可以避免动态内存分配的不确定性。 但是,cJSON库本身在解析过程中还会使用一些临时内存(例如解析字符串时),所以内存池大小需要留有余量。 参考文献: [^1]: cJSON 源码及文档:https://github.com/DaveGamble/cJSON 相关问题: 1. 如何确定静态内存池的大小? 2. 如何避免内存池碎片化? 3. 在多次解析JSON时,如何管理内存池的重置? 4. cJSON库中还有哪些其他的内存管理技巧? </think> ### cJSON库静态分配内存的使用方法 在cJSON库中实现静态分配内存(不使用动态内存分配)需要自定义内存管理函数并绑定到cJSON内存钩子(hooks),以下是具体步骤: #### 1. **定义静态内存池** 创建一个固定大小的静态缓冲区作为内存池: ```c #define MEM_POOL_SIZE 4096 // 根据需求调整大小 static uint8_t mem_pool[MEM_POOL_SIZE]; // 静态内存池 static size_t pool_index = 0; // 当前分配位置 ``` #### 2. **实现自定义分配/释放函数** ```c // 自定义malloc函数 void* static_malloc(size_t size) { if (pool_index + size > MEM_POOL_SIZE) { return NULL; // 内存不足 } void* ptr = &mem_pool[pool_index]; pool_index += size; return ptr; } // 自定义free函数(静态分配通常无需释放) void static_free(void* ptr) { // 空实现,或添加重置逻辑 } ``` #### 3. **初始化cJSON内存钩子** 在程序初始化时设置自定义函数: ```c cJSON_Hooks hooks; hooks.malloc_fn = static_malloc; hooks.free_fn = static_free; cJSON_InitHooks(&hooks); // 绑定到cJSON ``` #### 4. **使用cJSON创建对象** 创建JSON对象时将使用静态内存池: ```c // 创建JSON对象 cJSON* root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "name", "Device1"); cJSON_AddNumberToObject(root, "id", 1001); // 生成JSON字符串 char* json_str = cJSON_Print(root); printf("%s\n", json_str); // 清理(实际不会释放内存cJSON_Delete(root); ``` #### 5. **重置内存池(可选)** 需要重复使用时重置索引: ```c void reset_mem_pool() { pool_index = 0; // 重置分配位置 } ``` ### 关键注意事项 1. **内存池大小** 需确保`MEM_POOL_SIZE`足够大,需考虑: - JSON结构复杂度 - 字符串长度 - cJSON对象节点数量(每个约40字节) - 建议预留20%-30%余量 2. **生命周期管理** - 静态分配的内存**不会自动释放** - 可通过重置`pool_index`复用内存池 - 避免在JSON对象使用期间重置 3. **限制** ```mermaid graph LR A[静态分配优势] --> B[无内存碎片] A --> C[确定性内存使用] D[静态分配限制] --> E[固定内存上限] D --> F[不支持动态释放] D --> G[需预估最大需求] ``` 4. **替代方案** 对于嵌入式系统,可结合[^1]: - 内存池分块管理 - 环形缓冲区复用 - 部分预分配+部分动态分配 [^1]: cJSON官方文档中关于内存钩子的说明:https://github.com/DaveGamble/cJSON#hooks ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值