json-c需要注意的内存问题

此文为转载:https://blog.csdn.net/qiuoooooo/article/details/78643529

前言:

使用c库最关心的是内存谁来分配,谁来释放。json-c的内存管理方式,是基于引用计数的内存树(链)。

如果把一个struct json_object 对象a,add到另一个对象b上, 就不用显式的释放(json_object_put) a了, 相当于把a挂到了b的对象树上, 释放b的时候, 就会释放a。

当a即add到b上,又add到对象c上时会导致a被释放两次(double free),这时可以增加a的引用计数(调用函数json_object_get(a)),这时如果先释放b,后释放c,当释放b时,并不会真正的释放a,而是减少a的引用计数为1,然后释放c时,才真正释放a。

    理解了上面这点,使用json-c库,基本不会有什么问题了。

下面是进行分析哪些函数申请了内存:

1. json_object_get与json_object_put函数 
struct json_object* json_object_get(struct json_object *jso); // 将json对象的引用计数加1,返回jso自身
void json_object_put(struct json_object *jso); // 将jso对象的引用计数减1。此时如果json的引用计数大于0,直接返回; 如果json的引用计数为0,则递归的对每个子对象的引用计数减1,子对象引用计数为0时释放所占用内存。
注:如果对json对象显式调用了json_object_get,之后必须成对调用json_object_put,否则将导致该json对象所占用内存泄漏。

2. json_object_new_XXX系列函数 struct json_object* json_object_new_object(void);
struct json_object* json_object_new_int(int i);
struct json_object* json_object_new_double(double d);
struct json_object* json_object_new_array(void);
struct json_object* json_object_new_string(const char *s);
struct json_object* json_object_new_string_len(const char *s, int len);
json_object_new_XXX系列函数用来创建XXX类型的json对象,创建的json对象默认引用计数为1,因此在该对象使用完后也需要调用一次json_object_put来把引用计数置0,从而释放内存。

3. json_tokener_parse函数 
struct json_object* json_tokener_parse(const char *str);
json_tokener_parse将符合json格式的字符串构造为一个json对象,构造的json对象默认引用计数为1,同样需要在使用完后对该对象调用一次json_object_put。

4. is_error宏
is_error(jso)
如果传入的字符串是非法的json格式,错误判断应该使用is_error宏,而非 if(NULL != jso),CGI中目前有很多这种错误用法(虽然好像没引发什么问题)


5. json_object_object_XXX函数
void json_object_object_del(struct json_object* jso, const char *key);
从jso对象中删除键值为key的子对象,并释放该子对象及键值所占的内存(注:可能有文档说json_object_object_del只是删除而不释放内存,但实际上这是错误的)。
struct json_object* json_object_object_get(struct json_object* jso, const char *key); 从jso中获取键值为key的子对象。错误判断同样应该用is_error(jso)宏。
void json_object_object_add(struct json_object* jso, const char *key, struct json_object *val); 更新键值为key的子项的值。整个过程实际上是这样的:先从jso中删除并释放键值key及其值的内存,然后重新分配内存添加键值和新的值,所以json_object_object_add是包含json_object_object_del操作的。

6. json_object_get_XXX系列函数 
struct lh_table* json_object_get_object(struct json_object *jso);
const char* json_object_get_string(struct json_object *jso);
int json_object_get_int(struct json_object *jso);
double json_object_get_double(struct json_object *jso); 这类函数只是获取json对象的实际数据内容,不更新引用计数,也不分配内存。

7. json_object_array_XXX系列函数
struct json_object* json_object_array_get_sub_array(struct json_object *jso, int start_idx, int number);
这个函数用来从一个json数组对象中取数组序号start_idx开始的、总共number长度的子数组对象。分页显示功能常用到。注:返回的子数组是有重新分配内存的,所以同样要对返回的json_object*做一次json_object_put操作来释放内存。
int json_object_array_add(struct json_object *jso,struct json_object *val); 向数组中添加一个值。
int json_object_array_length(struct json_object *jso); 获取数组长度。
int json_object_array_put_idx(struct json_object *jso, int idx, struct json_object *val); 更新数组中序号为idx那一项的值,老的值同样会先被释放。
struct json_object* json_object_array_get_idx(struct json_object *jso, int idx); 获取数组中序号为idx那一项的json对象,不更新引用计数,也不分配内存。
struct json_object* json_object_array_sort(struct json_object *jso, const char *keyname, int sord ); 根据键值为keyname的项的值进行升序或降序排序,只是改变数组成员的顺序,不更新引用计数,也不分配内存。

猜你喜欢

转载自blog.csdn.net/langhaijing/article/details/82788461