Вопрос:

Связанный список с утечкой памяти

c memory-leaks linked-list

19 просмотра

1 ответ

301 Репутация автора

Я бьюсь головой с этой проблемой.

Если я проверяю свое приложение с помощью topкоманды в Linux, я получаю, что VIRTоно всегда одинаково (работает в течение нескольких дней), хотя RESнемного увеличивается (между 4 байтами и 32 байтами) после операции. Я выполняю операцию один раз каждые 60 минут.

Операция заключается в чтении некоторых кадров с помощью SPI, добавлении их в несколько связанных списков и, через некоторое время, извлечении их в другой поток.

Я выполнил Valgrind со следующими параметрами:

valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes -v ./application

Как только я закрываю его (мое приложение будет работать вечно, если все будет хорошо), я проверяю утечки и не вижу ничего, кроме потоков, которые я не закрыл. Только возможно потерянные байты в потоках. Нет точно и нет косвенно.

Я не знаю, нормально ли это. Я использовал Valgrind в прошлом, чтобы найти некоторые утечки, и это всегда работало хорошо, я уверен, что это работает хорошо и сейчас, но RESпроблему я не могу объяснить.

Я проверил связанный список, чтобы увидеть, не покидаю ли я некоторые узлы бесплатно, но мне кажется, это правильно.

У меня есть 32 связанных списка в одном массиве. Я сделал это, чтобы упростить операции push / pop, не имея 32 отдельных списков. Я не знаю, может ли это быть причиной проблемы. Если это так, я разделю их:

typedef struct PR_LL_M_node {
    uint8_t                 val[60];
    struct PR_LL_M_node     *next;
} PR_LL_M_node_t;

pthread_mutex_t         PR_LL_M_lock[32];
PR_LL_M_node_t          *PR_LL_M_head[32];
uint16_t                PR_LL_M_counter[32];

int16_t LL_M_InitLinkedList(uint8_t LL_M_number) {
    if (pthread_mutex_init(&PR_LL_M_lock[LL_M_number], NULL) != 0) {
        printf("Mutex LL M %d init failed\n", LL_M_number);
        return -1;
    }
    PR_LL_M_ready[LL_M_number]      = 0;
    PR_LL_M_counter[LL_M_number]    = 0;
    PR_LL_M_head[LL_M_number]       = NULL;
    pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);

    return PR_LL_M_counter[LL_M_number];
}

int16_t LL_M_Push(uint8_t LL_M_number, uint8_t *LL_M_frame, uint16_t LL_M_size) {

    pthread_mutex_lock(&PR_LL_M_lock[LL_M_number]);
    PR_LL_M_node_t *current = PR_LL_M_head[LL_M_number];
    if (current != NULL) {
        while (current->next != NULL) {
            current = current->next;
        }

        /* now we can add a new variable */
        current->next = malloc(sizeof(PR_LL_M_node_t));
        memset(current->next->val, 0x00, 60);                                                                                
        /* Clean buffer before using it */
        memcpy(current->next->val, LL_M_frame, LL_M_size);
        current->next->next = NULL;
    } else {
        PR_LL_M_head[LL_M_number] = malloc(sizeof(PR_LL_M_node_t));
        memcpy(PR_LL_M_head[LL_M_number]->val, LL_M_frame, LL_M_size);
        PR_LL_M_head[LL_M_number]->next = NULL;
    }
    PR_LL_M_counter[LL_M_number]++;
    pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);

    return PR_LL_M_counter[LL_M_number];
}

int16_t LL_M_Pop(uint8_t LL_M_number, uint8_t *LL_M_frame) {
    PR_LL_M_node_t  *next_node  = NULL;

    pthread_mutex_lock(&PR_LL_M_lock[LL_M_number]);
    if ((PR_LL_M_head[LL_M_number] == NULL)) {
       pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
        return -1;
    }

    if ((PR_LL_M_counter[LL_M_number] == 0)) {
        pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);
        return -1;
    }

    next_node = PR_LL_M_head[LL_M_number]->next;
    memcpy(LL_M_frame, PR_LL_M_head[LL_M_number]->val, 60);
    free(PR_LL_M_head[LL_M_number]);
    PR_LL_M_counter[LL_M_number]--;
    PR_LL_M_head[LL_M_number] = next_node;

    pthread_mutex_unlock(&PR_LL_M_lock[LL_M_number]);

    return PR_LL_M_counter[LL_M_number];
}

Таким образом, я передаю номер связанного списка, которым хочу управлять, и оперирую им. Как вы думаете? Это RESнастоящая проблема? Я думаю, что это может быть связано с другими частями приложения, но я закомментировал большую часть этого, и это всегда происходит, если используется операция push / pop. Если я оставляю push / pop, RESсохраняет его номер.

Когда я извлекаю значения, я использую do/, whileпока не получу -1ответ на операцию pop.

Автор: Biribu Источник Размещён: 11.08.2019 07:25

Ответы (1)


0 плюса

68398 Репутация автора

Ваши наблюдения не указывают на проблему:

  • VIRTи RESвыражаются в КиБ (единицы по 1024 байта). В зависимости от того, как работает виртуальная память в вашей системе, числа всегда должны быть кратны размеру страницы, который, скорее всего, составляет 4 КБ.
  • RES это объем резидентной памяти, другими словами, объем ОЗУ, фактически отображенный для вашей программы в данный момент времени.
  • Если программа переходит в спящий режим на 60 минут за один раз, система (Linux) может определить, что некоторые ее страницы являются хорошими кандидатами на удаление или замену, если ей необходимо сопоставить память для других процессов. RESбудет уменьшаться соответственно. Кстати, обратите внимание, что topэто один из таких процессов, который нуждается в памяти и, таким образом, может нарушить ваш процесс, наблюдая за ним, вычислительный вариант принципа Гейзенберга.
  • Когда процесс просыпается, любая память, к которой обращается запущенный поток, отображается обратно в память, либо из исполняемого файла (файлов), если он был удален, либо из файла подкачки, либо из ниоткуда, если удаленная страница была нулевыми байтами или неиспользованная часть стека. Это вызывает RESувеличение снова.

Могут быть другие проблемы в коде, особенно в коде, который вы не публиковали, но если VIRTон не изменяется, у вас, похоже, нет утечки памяти.

Автор: chqrlie Размещён: 11.08.2019 08:08
Вопросы из категории :
32x32