An issue with memory allocation in NRF52832 when working with JSON files

Hello,

I am using the NRF52832 processor on a custom board to collect data from a sensor and send it to a mobile app using BLE and NUS service in JSON format. However, after a few minutes, the transmission stops due to memory allocation failure.

Here is a piece of my code:

        root_G_P_R=cJSON_CreateObject();   

        cJSON_AddItemToObject(root_G_P_R, "info", info_G_P_R=cJSON_CreateObject());

        cJSON *plan_date = cJSON_CreateArray();

        for (int i= 0 ; i<APP_PlanCounter+1;i++)

        {

        cJSON_AddItemToArray(plan_date, cJSON_CreateNumber(APP_PlanDate[i]));

        }

        cJSON *TR = cJSON_CreateArray();

        for (int i= 0 ; i<APP_PlanCounter+1;i++)

        {

        cJSON_AddItemToArray(TR, cJSON_CreateNumber(APP_TRS[i]));

        }

        cJSON *TRCR = cJSON_CreateArray();

        for (int i= 0 ; i<APP_PlanCounter+1;i++)

        {

        cJSON_AddItemToArray(TRCR, cJSON_CreateNumber(App_TRCS[i]));

        }

        cJSON_AddItemToObject(root_G_P_R,    "key",            cJSON_CreateString("G_P_R"));

        cJSON_AddItemToObject(info_G_P_R,    "tr",     TR);

        cJSON_AddItemToObject(info_G_P_R,    "trac",     TRCR);

        cJSON_AddNumberToObject(info_G_P_R,  "plan",            plan);

        cJSON_AddNumberToObject(info_G_P_R,    "PT",           App_PT[APP_PlanCounter]);

        cJSON_AddItemToObject(info_G_P_R,    "date",           plan_date);

     if (print_preallocated(root_G_P_R) != 0) {

        cJSON_Delete(root_G_P_R);

        exit(EXIT_FAILURE);

    }

    cJSON_Delete(root_G_P_R);

and in the case of print_preallocated:

  static int print_preallocated(cJSON *root)

{

 

    char *out = NULL;

    char *buf = NULL;

    char *buf_fail = NULL;

    uint16_t len = 0;

    size_t len_fail = 0;

 

    out = cJSON_Print(root);

 

 

    len = strlen(out) + 5;

    buf = (char*)malloc(len);

 

   

    if (buf == NULL)

    {

        printf("Failed to allocate memory.\n");

        exit(1);

    }

    len_fail = strlen(out);

    buf_fail = (char*)malloc(len_fail);

    if (buf_fail == NULL)

    {

        printf("Failed to allocate memory.\n");

        exit(1);

    }

     ble_nus_data_send(&m_nus, (uint8_t *)out , &len, m_conn_handle);

    free(out);

    free(buf_fail);

    free(buf);

    return 0;

}

 

I have read in a thread that applying cJSON_Init() to the main would be helpful, but when I added this function, the JSON parse data process failed:

cJSON_Parse(received_data) --> cJSON_ParseWithOpts --> cJSON_New_Item --> cJSON_malloc

I suspect that there is something wrong with memory allocation. Could you please help me with this problem? Is there any configuration or consideration that I should have taken but missed out on?

 Thank you for your assistance.

  • Hi,

     

    I have read in a thread that applying cJSON_Init() to the main would be helpful, but when I added this function, the JSON parse data process failed:

    cJSON_Parse(received_data) --> cJSON_ParseWithOpts --> cJSON_New_Item --> cJSON_malloc

    I suspect that there is something wrong with memory allocation. Could you please help me with this problem? Is there any configuration or consideration that I should have taken but missed out on?

    What is the heap size set to on your end?

    Please note that you're using libc dynamic alloc functions, ie. "malloc()" instead of zephyr's kernel heap "k_malloc()"- this will use the heap by your selected libc (normally newlib or minimal libc, symbols NEWLIB_LIBC_MIN_REQUIRED_HEAP_SIZE / MINIMAL_LIBC_MALLOC_ARENA_SIZE)

     

    Kind regards,

    Håkon

  • Hi,
    Thank you for your prompt response.

    What is the heap size set to on your end?

    It's 8kb (0x20005910 - 0x2000790f).


    It seems that multiple function callings and transmitting the mentioned data cause the heap section to fill up after several uses. I have traced some allocated memory addresses in this scenario:


    allocated address : 200074dc
    allocated address : 2000741c
    allocated address : 200073dc
    allocated address : 200072dc
    allocated address : 2000728c
    allocated address : 200071cc
    allocated address : 2000717c
    allocated address : 200070fc
    allocated address : 2000709c
    allocated address : 2000706c
    allocated address : 20006fec
    allocated address : 20006fdc
    allocated address : 20006f2c
    allocated address : 20006e9c
    allocated address : 20006e2c
    allocated address : 20006dac
    allocated address : 20006d3c
    allocated address : 20006d2c
    allocated address : 20006c4c
    allocated address : 20006bdc
    allocated address : 20006b6c
    allocated address : 20006b3c
    allocated address : 20006afc
    allocated address : 20006acc
    allocated address : 20006a8c
    allocated address : 20006a7c
    allocated address : 200069cc
    allocated address : 200068fc
    allocated address : 200068cc
    allocated address : 2000681c
    allocated address : 2000677c
    allocated address : 2000673c
    allocated address : 2000669c
    allocated address : 2000664c
    allocated address : 2000657c
    allocated address : 2000655c
    allocated address : 200064dc
    allocated address : 200063ec
    allocated address : 200063cc
    allocated address : 2000635c
    allocated address : 200062ec
    allocated address : 2000626c
    allocated address : 2000619c
    allocated address : 2000611c
    allocated address : 2000609c
    allocated address : 2000608c
    allocated address : 2000601c
    allocated address : 20005fac
    allocated address : 20005f3c
    allocated address : 20005edc
    allocated address : 20005e9c
    allocated address : 20005e4c
    allocated address : 20005ddc
    allocated address : 20005d7c
    allocated address : 20005d1c
    allocated address : 20005cec
    allocated address : 20005c5c
    allocated address : 20005bec
    allocated address : 20005b5c
    allocated address : 20005b1c
    allocated address : 20005b8c
    allocated address : 20005b2c
    allocated address : 20005a4c

    As you may have noticed, the beginning and end of these addresses are quite close to the start and end of the heap section. Is there anything I can do to prevent this? My goal is for users to be able to access this data as frequently as they desire through the mobile app, but it currently only works for a limited time.

    I appreciate the time you have taken.

    ZaQa

  • Hi ZaQa,

     

    ZaQa said:
    It seems that multiple function callings and transmitting the mentioned data cause the heap section to fill up after several uses. I have traced some allocated memory addresses in this scenario:

    You can lock the function with a semaphore for instance.

    The allocation print indicate that you're not free'ing the data? It only goes in one direction.

    You have to debug to see where the memory is leaking.

     

         ble_nus_data_send(&m_nus, (uint8_t *)out , &len, m_conn_handle);

    Sorry, I assumed you were using NCS, but this function call points to nRF5 SDK.

     

    You must check your return here, if not; you risk losing data.

    In general, I would recommend that you check your returned pointers, also from the cJSON_* calls as well.

     

    Kind regards,

    Håkon

  • You must check your return here, if not; you risk losing data.

    That's correct. I investigated and now I'm verifying the value returned by the ble_nus_data_send function, which seems to be working properly.

    Upon thoroughly examining my code, I have come to the realization that the free() function does not release allocated space. Consequently, over time, the heap section becomes full and ultimately causes the code to fail.

    Could you please guide me on how to effectively resolve this issue? I would greatly appreciate your kind assistance.

  • Hi,

     

    Dynamic memory handling is not always easy to handle, and should ideally only be used when there's no other option.

    cJSON is one scenario where it makes sense to use dynamic allocation.

     

    ZaQa said:
    Upon thoroughly examining my code, I have come to the realization that the free() function does not release allocated space. Consequently, over time, the heap section becomes full and ultimately causes the code to fail.

    Which compiler are you using? is alloc used in other functions of your firmware?

     

    Kind regards,

    Håkon

Related