事故起因
代码运行后没几分钟系统就崩溃重启,看了一下是内存分配不出来了,通过不断注释代码排除后锁定到cJSON库上。
问题调查1
看了一下cJSON库中的注释,发现这么一句话:
Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer.
Supply a block of JSON, and this returns a cJSON object you can interrogate.
大概意思是调用cJSON_Parse和cJSON_Print与这两个函数的任何变体时,调用者需自行释放内存
于是写了这么两个函数
void *kvstore_print(KeyValueStore *kvstore, char *json_str)
{
char *str = cJSON_Print(kvstore->root);
strcpy(json_str, str);
cJSON_free(str);
}
int linkkit_get_value_int(const char *json_str, char *key, int *value)
{
cJSON *root = NULL;
cJSON *item = NULL;
root = cJSON_Parse(json_str);
if (root == NULL)
{
printf("parse json failed\n");
return -1;
}
item = cJSON_GetObjectItem(root, key);
if (item == NULL)
{
printf("No key\n");
return -2;
}
*(int *)value = item->valueint;
cJSON_Delete(root);
return 0;
}
问题调查2
经过在上面这两个函数中添加释放内存的操作后,系统没有那么快崩溃了,但是我不停查看剩余内存后发现内存依然在泄露,于是上网查找其他大佬的心得,看到了这篇文章
原来在使用cJSON_Create及其变体时也需要手动释放内存,于是修改函数如下:
void kvstore_add_str(KeyValueStore *kvstore, const char *key, const char *value)
{
if (kvstore && key)
{
cJSON *val = cJSON_CreateString(value);
kvstore_add(kvstore, key, val);
cJSON_Delete(val);
}
}
问题调查3
经过前面两步,我观察到每走一次业务流程的内存泄露从5.5KBytes变成了64Bytes,这么稳定且小的内存泄漏很容易发现原因:初始kvstore时手动分配了一个KeyValueStore的结构体,在反初始化代码中添加一句free即可解决
void kvstore_free(KeyValueStore *kvstore)
{
if (kvstore)
{
cJSON_Delete(kvstore->root);
cJSON_free(kvstore);
}
}
总结
- 在调用cJSON_Parse、cJSON_Print、cJSON_Create这三个函数及其变体时,使用者需要手动释放其返回值的内存
- 在KeyValueStore结构体使用完毕后,需要手动释放其自身