Skip to content

Maybe a terrible bug in the multi-threaded usage scenario #1497

@hizilla

Description

@hizilla

Hi, guys, I used jemalloc as a memory allocator in my project recently. However, I found that there is a serious problem that dirty pages are not released in the multi-threaded usage scenario.

The conditions under which dirty pages are not released are as follows:
1.Thread A frees memory allocated by other threads;
2.Thread A did not apply for memory before freeing memory in step 1.

In order to confirm this problem, I read the source code of jemalloc. Finally I found out that under the above conditions arenas_tdata in tsd_tls always be NULL because arenas_tdata_bypass has been set true during first free.

This problem has been extended from adding the decay_time recycling version to the latest version.

Here is the demo code you can test :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

#define TEST_BUFF_MAX_NUM 2500
#define TEST_BUFF_SIZE 1090

void *g_test_buff;

void *test_leak_buff[TEST_BUFF_MAX_NUM];

void test_thread(void)
{
    int i;

    /*1st. free the memory allocated in other thread*/
    if (g_test_buff)
    {
        free(g_test_buff);
    }

    /*2nd. here we go, malloc and free memory*/
    while(1)
    {
        for (i = 0; i < TEST_BUFF_MAX_NUM; i++)
        {
            test_leak_buff[i] = malloc(TEST_BUFF_SIZE);
            if (test_leak_buff[i] == NULL)
            {
                printf("malloc failed!\n");
                while (1);/*just halt*/
            }
            memset(test_leak_buff[i], 0, TEST_BUFF_SIZE);
        }

        sleep(1);

        for (i = 0; i < TEST_BUFF_MAX_NUM; i++)
        {
            free(test_leak_buff[i]);
        }
    }
}

int main(int argc, char **argv)
{
    pthread_t tid;

    g_test_buff = malloc(TEST_BUFF_SIZE);
    if (g_test_buff == NULL)
    {
        printf("malloc failed.");
        while(1);
    }

    if (pthread_create(&tid, NULL, (void*)test_thread, NULL) < 0)
    {
        printf("create test_thread failed.\n");
    }

    while (1)
    {
        sleep(1);
    }

    return 0;
}

The following is the statistical result of the program running for a period of time :

decaying:  time       npages       sweeps     madvises       purged
   dirty:   N/A        48115            0            0            0
   muzzy:   N/A            0            0            0            0
                            allocated     nmalloc     ndalloc   nrequests
small:                        3255048      158833      156241      159997
large:                          57344           2           0           2
total:                        3312392      158835      156241      159999

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions