Управление памятью и перераспределение - PullRequest
8 голосов
/ 23 октября 2009

Я перебираю свою программу с помощью valgrind, чтобы выследить утечки памяти. Вот тот, с которым я не уверен, что делать.

==15634== 500 (224 direct, 276 indirect) bytes in 2 blocks are definitely lost in loss record 73 of 392
==15634==    at 0x4007070: realloc (vg_replace_malloc.c:429)
==15634==    by 0x807D5C2: hash_set_column(HASH*, int, char const*) (Hash.cpp:243)
==15634==    by 0x807BB15: LCD::PluginDiskstats::PluginDiskstats() (PluginDiskstats.cpp:102)
==15634==    by 0x806E021: LCD::Evaluator::Evaluator() (Evaluator.cpp:27)
==15634==    by 0x8066A87: LCD::LCDControl::LCDControl() (LCDControl.h:16)
==15634==    by 0x80667F5: main (Main.cpp:8)

Вот код:

/* add an entry to the column header table */
void hash_set_column(HASH * Hash, const int number, const char *column)
{
    if (Hash == NULL)
        return;

    Hash->nColumns++;
    Hash->Columns = (HASH_COLUMN *)realloc(Hash->Columns, Hash->nColumns * sizeof(HASH_COLUMN)); // line 243
    Hash->Columns[Hash->nColumns - 1].key = strdup(column);
    Hash->Columns[Hash->nColumns - 1].val = number;

    qsort(Hash->Columns, Hash->nColumns, sizeof(HASH_COLUMN), hash_sort_column);

}

Должен ли я что-то здесь делать в отношении управления памятью?

Ответы [ 6 ]

11 голосов
/ 23 октября 2009

Проблема заключается в том, что в случае сбоя realloc() функция вернет NULL, но исходный блок все равно будет выделен. Однако вы просто перезаписали указатель на этот блок и больше не можете его (или использовать).

2 голосов
/ 23 октября 2009

Valgrind не говорит, что утечка происходит в строке realloc - он говорит, что память, выделенная этой строкой realloc, является утечкой памяти, в конце концов. Вальгринд не знает, где, хотя - он просто знает, что у вас больше нет ссылки на эту память, так что было бы невозможно free ее использовать. (ОП может знать это, но ясно, что многие из ответивших не знают!)

Короче говоря, код, который вы вставили, не вызывает проблемы (хотя проблема, которую поднимает Майкл Берр, определенно реальна, но, поскольку вы даже не проверяете NULL, возвращенный из realloc .. .)

Где-то в вашем коде должен быть free(Hash->Columns), которого сейчас нет. Найдите это место - вероятно, непосредственно перед освобождением Hash - и добавьте его.

2 голосов
/ 23 октября 2009

Если realloc () завершается с ошибкой, возвращается ноль и исходный блок не освобождается . Эта строка:

Hash->Columns = (HASH_COLUMN *)realloc(Hash->Columns, Hash->nColumns * sizeof(HASH_COLUMN)); // line 243

не проверяет возвращаемое значение. Таким образом, если realloc () завершается с ошибкой, null записывается в Hash-> Columns и исходный блок просачивается.

1 голос
/ 23 октября 2009

Ага - комментарий асвейкау:

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

привел меня к другой проблеме - изменяемая структура данных содержит указатели на строки, выделенные с помощью strdup(). если ваш realloc() вызов делает выделение меньшим, вы потеряете эти указатели, не освободив их должным образом. Я считаю, что Асвейкау прав, что именно на это жалуется Вальгринд.

1 голос
/ 23 октября 2009

Не уверен, что это проблема, но это потенциально проблематично. С справочной страницы для realloc():

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном завершении с размером, не равным 0, realloc() возвращает указатель на (возможно, перемещенный) выделенное пространство. Если размер равен 0, возвращается либо нулевой указатель, либо уникальный указатель, который может быть успешно передан в free(). Если доступной памяти недостаточно, realloc() возвращает нулевой указатель и устанавливает errno [ENOMEM].

Что произойдет, если недостаточно места для развернутого объекта, старый объект все еще действует и не освобождается, но realloc() возвращает NULL. Таким образом, вы должны сохранить возвращаемый результат realloc() в отдельной переменной, проверить эту переменную на NULL, а если это не так, присвоить Hash->Columns.

0 голосов
/ 23 октября 2009

В Mac OS X и FreeBSD et al. у вас также есть функция reallocf ():

man 3 malloc | less -p reallocf 
... 
     The reallocf() function is identical to the realloc() function, except
 that it will free the passed pointer when the requested memory cannot be
 allocated.  This is a FreeBSD specific API designed to ease the problems
 with traditional coding styles for realloc causing memory leaks in
 libraries.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...