Анализ результатов Valgrind memcheck парсера бизонов / флекс - PullRequest
0 голосов
/ 22 июня 2011

Я запускаю memcheck в своей программе и пытаюсь решить проблемы с памятью.

Вывод Memcheck:

==29633== 3,443 (128 direct, 3,315 indirect) bytes in 2 blocks are definitely lost in loss record 7 of 8
==29633==    at 0x4A07D2E: operator new(unsigned long) (vg_replace_malloc.c:261)
==29633==    by 0x42027F: PDcbk(cpfrCallbackType_e, Powerdomain*) (NetExtractor.cpp:1243)
==29633==    by 0x413DBA: cpfparse() (cpf.y:120)
==29633==    by 0x42039B: loadCPF(char*) (NetExtractor.cpp:1253)
==29633==    by 0x420E5D: main (NetExtractor.cpp:1399)
==29633== LEAK SUMMARY:
==29633==    definitely lost: 128 bytes in 2 blocks
==29633==    indirectly lost: 3,315 bytes in 10 blocks
==29633==      possibly lost: 0 bytes in 0 blocks
==29633==    still reachable: 16,458 bytes in 3 blocks
==29633==         suppressed: 0 bytes in 0 blocks

Строка 1253 NetExtractor:

powerdomainMap.insert(Powerdomain_pair(powerdomain->getName(),new Powerdomain(*powerdomain)));

Информация, чтобы понять код:

PowerdomainHashMap powerdomainMap;

typedef hash_map<const string, Powerdomain*, strptrhash, strptrequal> PowerdomainHashMap;
typedef pair<const string, Powerdomain*> Powerdomain_pair;

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

Я прав? Если нет, может кто-нибудь объяснить мне?

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

Ответы [ 4 ]

1 голос
/ 22 июня 2011

Вы выделяете память в вашей операции вставки, это когда-либо освобождается должным образом?

Я бы рекомендовал использовать контейнеры STL, которые минимизируют объем кода, который вы должны написать:

#include <unordered_map>
#include <string>
#include <memory>

typedef std::unordered_map<std::string, std::shared_ptr<Powerdomain> > PowerdomainMap;

Это должно иметь все необходимые вам функции со встроенной безопасностью памяти.

В C ++ 98 используйте <tr1/unordered_map> и std::tr1::unordered_map и т. Д.

1 голос
/ 22 июня 2011

В разделе часто задаваемых вопросов руководства, которое поставляется с каждым valgrind, есть:

Моя программа использует C ++ STL и строковые классы.Valgrind сообщает о «все еще достижимых» утечках памяти, связанных с этими классами, при выходе из программы, но их не должно быть.

Прежде всего: расслабьтесь, это, вероятно, не ошибка, а особенность.Многие реализации стандартных библиотек C ++ используют свои собственные распределители пула памяти.Память для большого количества разрушенных объектов не сразу освобождается и возвращается ОС, но хранится в пуле (ах) для последующего повторного использования.Тот факт, что пулы не освобождаются при выходе из программы, заставляет Valgrind сообщать о том, что эта память все еще доступна.Однако поведение, не позволяющее освобождать пулы на выходе, можно назвать ошибкой библиотеки.

Используя GCC, вы можете заставить STL использовать malloc и как можно скорее освободить память, отключив глобальное кэширование памяти.Осторожно!Это, вероятно, замедлит вашу программу, иногда радикально.

• С GCC 2.91, 2.95, 3.0 и 3.1 скомпилируйте весь исходный код, используя STL с -D__USE_MALLOC.Осторожно!Это было удалено из GCC, начиная с версии 3.3.

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

• В GCC 3.4 и более поздних версияхэта переменная сменила имя на GLIBCXX_FORCE_NEW.

Существуют и другие способы отключить пул памяти: использование шаблона malloc_alloc с вашими объектами (не переносимым, но должно работать для GCC) или даже запись собственных распределителей памяти.Но все это выходит за рамки этого FAQ.Начните с чтения http://gcc.gnu.org/onlinedocs/libstdc++/faq/index.html#4_4_leak, если вы абсолютно хотите это сделать.Но будьте осторожны: распределители принадлежат к более грязным частям STL, и люди пошли на многое, чтобы сделать STL переносимым между платформами.Скорее всего, ваше решение будет работать на вашей платформе, но не на других.

Возможно, ваша проблема связана.

1 голос
/ 22 июня 2011

Ну, у вас есть карта указателей на динамически размещенные объекты класса Powerdomain. Хеш-карта сама по себе не выделяла эту память, поэтому она не очищает ее для вас. Что вам нужно сделать, так это освободить эту память самостоятельно, если она вам не нужна, например:

for (PowerdomainHashMap::iterator i = powerdomainMap.begin (),
     e = powerdomainMap.end (); i != e; ++i)
{
    delete i->second;
}
powerdomainMap.clear ();

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

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

Кроме того, похоже, что вы все равно делаете копии объектов, поэтому я думаю, что стоит подумать о том, чтобы явно не работать с динамической памятью, и пусть hash_map беспокоится об этом. Объявление типа данных будет выглядеть так:

typedef hash_map<const string, Powerdomain, strptrhash, strptrequal> PowerdomainHashMap;
typedef pair<const string, Powerdomain> Powerdomain_pair;

Надеюсь, это поможет.

1 голос
/ 22 июня 2011

Утечка памяти в соответствии с memcheck - это любой блок памяти, выделенный в течение времени жизни программы, который не освобождается при выходе из программы. Поскольку вы храните указатель в hash_map, этот указатель остается несвободным при уничтожении hash_map. Вы должны либо использовать shared_ptr в hash_map, либо использовать коллекцию, которая принимает указатель и удаляет его при уничтожении коллекции.

...