从 jansson libary 创建 json 请求时释放内存的正确方法是什么?

问题描述 投票:0回答:2

我正在使用 janson 库发送 json 正文作为其余请求,我注意到我正在这样做:

json_t *json_body = json_object();
char sentString[100];
char sentStringSecond[100];
..
json_object_set_new(json_body, "sentString", json_string(sentString));
json_object_set_new(json_body, "sentStringSecond", json_string(sentStringSecond);
..
json_decref(json_body);     

对 json_decref 的一次调用是否足以释放所有内存? 我的担忧主要是读完这篇文章后 json_decref 不释放内存?

c memory-leaks jansson
2个回答
4
投票

您正在使用不同的函数来设置 JSON 字符串:

json_object_set_new
而不是链接问题中的
json_object_set

您的版本将元素添加到 json 对象并“重用”引用。它不会增加计数器。 因此您不需要手动递减它。 该问题答案下面的评论也提到了

json_object_set_new

添加的元素将与主 JSON 对象一起被释放

json_body
。 这意味着所有子对象的引用计数器都会自动递减。如果计数器降至 0,则该对象被释放。

如果您自己持有对子对象的引用,则该对象将不会被释放。

举个例子:

您创建一个对象(调用

json_string()
),它将获得引用计数==1。

变体a)(来自链接的问题)

您可以将此对象添加到具有新引用的另一个对象。 这是使用

json_object_set
完成的。然后计数器增加到 2。

如果删除主对象(

json_decref(json_body)
),计数器再次降至1,但字符串仍然没有释放。 您需要使用
json_decref(srting)
来释放内存。

变体 b)(您的代码)

您可以将此对象添加到另一个对象并移交现有引用。 这是使用

json_object_set_new
完成的。然后计数器保留值 1。

如果删除主对象 (

json_decref(json_body)
) 计数器将降至 0,现在字符串与主对象一起被释放。 您不需要使用
json_decref(srting)
来释放内存。


0
投票

当我们在jansson库中创建一个json对象时,它的类型是'json_t'。该库使用引用计数来管理对象的清理。内部调用malloc和free进行内存管理;每当我们创建一个对象 json_t * obj 时,都会分配内存,并且在引用计数不为空之前不会释放该对象。

文档中经常提到的术语“窃取引用”意味着对象引用计数被借用,并且一旦对象被消耗,计数就不会增加。因此,lib 中的所有“.._new” api 都可以让您以更干净的方式编写,而无需大惊小怪 decref - json 对象中的各个元素。

我自己必须阅读文档和示例才能为此 json_decref 创建这个综合答案。我试图保持简单并使用 valgrind 来获得更好的理解。以下是示例:

  1. 当子对象被创建为 json 对象(父对象)中的节点时 -> 清理父对象也会清理子对象
  2. 当多个json对象添加到一个json数组对象时 -> 清理json数组对象会清理下级节点
  3. 当未使用 '_new' api 且使用例如 'json_object_set(..)' 创建对象时 -> 显式清理单个元素

示例1:

代码

    #include <stdio.h>
#include <stdlib.h>
#include <jansson.h>

int main(){

int a =5;
//char * str = malloc(sizeof(a)*4);
printf("str allocated\n");
json_t * obj = json_object();
json_t * obj2 = json_object();
json_object_set_new(obj, "node", obj2);
json_object_set_new(obj, "num", json_integer(a));
json_object_set_new(obj, "num", json_integer(a));
json_object_set_new(obj2, "num3", json_integer(2));
json_object_set_new(obj2, "num4", json_integer(28));
json_object_set_new(obj, "str", json_string("name"));

 char * s = json_dumps(obj, JSON_COMPACT | JSON_INDENT(2));
        printf("json is [%s]", s);
        free(s);
//json_decref(obj);
json_decref(obj2);

return 0;
}

cli 输出

charulata@charulata-virtual-machine:~$ vi test_val_json.c 
charulata@charulata-virtual-machine:~$ gcc -o json_v test_val_json.c -ljansson 
charulata@charulata-virtual-machine:~$ valgrind ./json_v
==5676== Memcheck, a memory error detector
==5676== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5676== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==5676== Command: ./json_v
==5676== 
str allocated
json is [{
  "node":{
    "num3":2,
    "num4":28
  },
  "num":5,
  "str":"name"
}]==5676== 
==5676== HEAP SUMMARY:
==5676==     in use at exit: 418 bytes in 8 blocks
==5676==   total heap usage: 24 allocs, 16 frees, 2,378 bytes allocated
==5676== 
==5676== LEAK SUMMARY:
==5676==    definitely lost: 72 bytes in 1 blocks
==5676==    indirectly lost: 346 bytes in 7 blocks
==5676==      possibly lost: 0 bytes in 0 blocks
==5676==    still reachable: 0 bytes in 0 blocks
==5676==         suppressed: 0 bytes in 0 blocks
==5676== Rerun with --leak-check=full to see details of leaked memory
==5676== 
==5676== For lists of detected and suppressed errors, rerun with: -s
==5676== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

示例2:

代码

#include <stdio.h>
#include <stdlib.h>
#include <jansson.h>

int main(){

json_t * res = json_object();
json_object_set_new(res, "state", json_string("up"));
json_t * jcards = json_array();
json_object_set_new(res, "cards", jcards);

for ( int i = 0; i <2; i++){

int a =5;
//char * str = malloc(sizeof(a)*4);
printf("str allocated\n");
json_t * obj = json_object();
json_array_append_new(jcards, obj);
json_object_set_new(obj, "num", json_integer(a));
json_object_set_new(obj, "num", json_integer(a));
json_object_set_new(obj, "num3", json_integer(2));
json_object_set_new(obj, "num4", json_integer(2));
json_object_set_new(obj, "str", json_string("name"));


json_t * new = json_object_get(res, "cards");
 char * k = json_dumps(new, JSON_COMPACT | JSON_INDENT(2));
        printf("json is [%s]", k);
        free(k);

 char * s = json_dumps(obj, JSON_COMPACT | JSON_INDENT(2));
        printf("json is [%s]", s);
        free(s);
//json_decref(obj); /*not required as parent obj is being cleaned*/
}
//json_decref(jcards); /*not required as parent obj is being cleaned, arr is part of json obj here 'res'*/ 
json_decref(res);

return 0;
}
              

cli 输出

charulata@charulata-virtual-machine:~$ vi test_json_arr_obj.c 
charulata@charulata-virtual-machine:~$ gcc -o json_arr test_json_arr_obj.c -ljansson 
charulata@charulata-virtual-machine:~$ valgrind ./json_arr 
==5798== Memcheck, a memory error detector
==5798== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5798== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==5798== Command: ./json_arr
==5798== 
str allocated
json is [[
  {
    "num":5,
    "num3":2,
    "num4":2,
    "str":"name"
  }
]]json is [{
  "num":5,
  "num3":2,
  "num4":2,
  "str":"name"
}]str allocated
json is [[
  {
    "num":5,
    "num3":2,
    "num4":2,
    "str":"name"
  },
  {
    "num":5,
    "num3":2,
    "num4":2,
    "str":"name"
  }
]]json is [{
  "num":5,
  "num3":2,
  "num4":2,
  "str":"name"
}]==5798== 
==5798== HEAP SUMMARY:
==5798==     in use at exit: 0 bytes in 0 blocks
==5798==   total heap usage: 63 allocs, 63 frees, 4,750 bytes allocated
==5798== 
==5798== All heap blocks were freed -- no leaks are possible
==5798== 
==5798== For lists of detected and suppressed errors, rerun with: -s
==5798== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

示例3:

案例1:内存泄漏

    #include <stdio.h>
#include <stdlib.h>
#include <jansson.h>

int main(){


int a =5;
json_t * obj = json_object();
//json_object_set_new(obj, "num3", json_integer(2));
json_object_set(obj, "num3", json_integer(2));  /*this json_integer object is not freed*/
json_object_set_new(obj, "num4", json_integer(2));
json_object_set_new(obj, "str", json_string("name"));


char * s = json_dumps(obj, JSON_COMPACT | JSON_INDENT(2));
printf("json is [%s]", s);
free(s);

json_decref(obj);

return 0;
}

cli 输出

charulata@charulata-virtual-machine:~$ vi test_json_set_new.c 
charulata@charulata-virtual-machine:~$ gcc -o json_s_new test_json_set_new.c -ljansson 
charulata@charulata-virtual-machine:~$ valgrind ./json_s_new 
==6274== Memcheck, a memory error detector
==6274== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6274== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==6274== Command: ./json_s_new
==6274== 
json is [{
  "num3":2,
  "num4":2,
  "str":"name"
}]==6274== 
==6274== HEAP SUMMARY:
==6274==     in use at exit: 24 bytes in 1 blocks
==6274==   total heap usage: 16 allocs, 15 frees, 1,808 bytes allocated
==6274== 
==6274== LEAK SUMMARY:
==6274==    definitely lost: 24 bytes in 1 blocks
==6274==    indirectly lost: 0 bytes in 0 blocks
==6274==      possibly lost: 0 bytes in 0 blocks
==6274==    still reachable: 0 bytes in 0 blocks
==6274==         suppressed: 0 bytes in 0 blocks
==6274== Rerun with --leak-check=full to see details of leaked memory
==6274== 
==6274== For lists of detected and suppressed errors, rerun with: -s
==6274== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

情况 2:递减单个元素

#include <stdio.h>
#include <stdlib.h>
#include <jansson.h>

int main(){

int a =5;
json_t * obj = json_object();
json_t *val = json_integer(2);
json_object_set(obj, "num3", val);  /*this json_integer object is not freed by itself, exclusively decref is called for this element*/
json_object_set_new(obj, "num4", json_integer(3));
json_object_set_new(obj, "str", json_string("name"));


char * s = json_dumps(obj, JSON_COMPACT | JSON_INDENT(2));
printf("json is [%s]", s);
free(s);

json_decref(obj);
json_decref(val);

return 0;
}

cli 输出

charulata@charulata-virtual-machine:~$ gcc -o json_s_new test_json_set_new.c -ljansson 
charulata@charulata-virtual-machine:~$ valgrind ./json_s_new 
==6515== Memcheck, a memory error detector
==6515== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6515== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==6515== Command: ./json_s_new
==6515== 
json is [{
  "num3":2,
  "num4":3,
  "str":"name"
}]==6515== 
==6515== HEAP SUMMARY:
==6515==     in use at exit: 0 bytes in 0 blocks
==6515==   total heap usage: 16 allocs, 16 frees, 1,808 bytes allocated
==6515== 
==6515== All heap blocks were freed -- no leaks are possible
==6515== 
==6515== For lists of detected and suppressed errors, rerun with: -s
==6515== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

情况 3:使用 '_new' api 窃取引用

    #include <stdio.h>
#include <stdlib.h>
#include <jansson.h>

int main(){

int a =5;
json_t * obj = json_object();
json_t *val = json_integer(2);
json_object_set(obj, "num3", val);  /*this json_integer object is not freed by itself, exclusively decref is called for this element*/
json_object_set_new(obj, "num3", val);  /*this json_integer object is freed by itself*/
json_object_set_new(obj, "num4", json_integer(3));
json_object_set_new(obj, "str", json_string("name"));

char * s = json_dumps(obj, JSON_COMPACT | JSON_INDENT(2));
printf("json is [%s]", s);
free(s);

json_decref(obj);
//json_decref(val);

return 0;
}

cli 输出

charulata@charulata-virtual-machine:~$ gcc -o json_s_new test_json_set_new.c -ljansson 
charulata@charulata-virtual-machine:~$ valgrind ./json_s_new 
==6533== Memcheck, a memory error detector
==6533== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6533== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==6533== Command: ./json_s_new
==6533== 
json is [{
  "num3":2,
  "num4":3,
  "str":"name"
}]==6533== 
==6533== HEAP SUMMARY:
==6533==     in use at exit: 0 bytes in 0 blocks
==6533==   total heap usage: 16 allocs, 16 frees, 1,808 bytes allocated
==6533== 
==6533== All heap blocks were freed -- no leaks are possible
==6533== 
==6533== For lists of detected and suppressed errors, rerun with: -s
==6533== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
© www.soinside.com 2019 - 2024. All rights reserved.