akheron / jansson

C library for encoding, decoding and manipulating JSON data
http://www.digip.org/jansson/
Other
3.05k stars 808 forks source link

I can't understand why I have memory leak, please help. #600

Closed krishna116 closed 2 years ago

krishna116 commented 2 years ago

Now I am learning how to using this jansson library, I'm not very clear about the memory management in this library, so I write a small test to test my idea and I found memory leak, this is my test code:

// using visual studio 2019, console application(x86). // using jansson-version: 2.13.1

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>     // debug memory leak.
#include <jansson.h>
#include <stdio.h>

void test()
{
    static const char str[] = "[{\"key1\":\"value1\"},{\"key2\":\"value2\"},{\"key3\":\"\"}]";
    json_t* root;
    json_error_t error;
    root = json_loads(str, 0, &error);

    if (json_is_array(root))
    {
        json_t* kv = json_object();
        json_object_set(kv, "key4", json_string("value4")); //create a new key-value pair;

        int result = json_array_append(root, kv);   // append the new key-value pair;
        printf("json_array_append result = %d\n",result); // result is 0;
    }

    if (root)
    {
        json_decref(root);
    }
}

int main()
{
    _CrtMemState snapshot1;
    _CrtMemState snapshot2;
    _CrtMemState diff;
    _CrtMemCheckpoint(&snapshot1); //take a snapshot for memory usage.

    printf("--------------------begin--test\n");
    test();
    printf("--------------------end--test\n");

    _CrtMemCheckpoint(&snapshot2); //take a snapshot for memory usage.
    if (_CrtMemDifference(&diff, &snapshot1, &snapshot2)) // if there is a difference
    {
        _CrtDumpMemoryLeaks();
    }

    return 0;
}

and there are some APIs I don't very clear, for example: json_object_set(json_t object, const char key, json_t *value) question: if (json_object_set ok), the key buffer will attached to the object tree and key's life time is managed by the object? if (json_object_set fail), the key buffer is managed by caller? if (json_object_set ok), the value buffer will attached to the object tree and value buffer's life time is managed by the object? if (json_object_set fail), the value buffer is managed by caller?

can sombody explain?

thank you!

akheron commented 2 years ago

It's all explained in the docs: https://jansson.readthedocs.io/en/latest/apiref.html#reference-count

In a nutshell: If you create a new JSON value, you must call json_decref() to release your reference to it. If you use a function that steals the reference (these functions end with _new), you must not call json_decref() anymore.

In your example, these references are leaked:

krishna116 commented 2 years ago

It is a interesting design, I have traced the reference count, if I use json_array_append(root, kv), the kv's reference count will increase to 2, if I use json_array_append_new(root, kv), the kv's reference count will stay at 1, thank you for the explain, I think I understand it now.