Обнаружение утечки памяти GCC эквивалентно Microsoft crtdbg.h? - PullRequest
25 голосов
/ 19 ноября 2009

После многих лет работы над универсальной библиотекой C ++ с использованием компилятора Microsoft MSVC в Visual Studio мы теперь переносим ее на Linux / Mac OS X (молитесь за нас). Я привык и очень люблю простой механизм обнаружения утечек памяти в MSVC:

#ifdef DEBUG
    #define _CRTDBG_MAP_ALLOC
    #define NEW   new( _NORMAL_BLOCK, __FILE__, __LINE__)
    #include <stdlib.h>
    #include <crtdbg.h>
#else
    #define NEW   new
#endif

Каждое распределение памяти выполняется с помощью этого НОВОГО макроса. Всякий раз, когда процесс, использующий нашу библиотеку, завершается, любые утечки памяти (блоки, которые не были выделены) сообщаются на консоли вместе с файлом и строкой #, где память была первоначально выделена.

Мне нравится то, что мне не нужно активно «работать с инструментом повышения производительности» или иным образом указывать, что я ищу утечки. Утечки сообщаются мне в ходе обычной разработки, каждый раз, когда процесс завершается.

Теперь, когда мы переходим в мир GCC, я обнаружил, что инструменты обнаружения утечек памяти, многие из которых довольно сложны, требуют, чтобы я явно указал, что я нахожусь в режиме поиска утечек. Моя IDE - это Xcode, и я изучил некоторые инструменты выделения / обнаружения утечек (например, Instruments и MallocDebug), но признаю, что еще не потратил время, чтобы полностью разобраться с ними. Меня все время отталкивает тот факт, что я на самом деле должен указать, что я ищу утечку раньше времени, вместо того, чтобы автоматически получать уведомление об этом.

Я использую Xcode 3.2, и я слышал, что теперь есть отличная интеграция с инструментом статического анализа, но опять же я не изучал это. Я ищу некоторое представление о том, что мои варианты. Существует ли сопоставимый механизм, встроенный в GCC и / или XCode? Есть ли простая сторонняя библиотека или инструмент, который выполняет самые основные функции, которые я знаю и люблю? Или я должен смириться с этим и изучить новый способ ведения дел?

Ответы [ 6 ]

19 голосов
/ 19 ноября 2009

Вам доступно несколько вариантов.

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

Во-вторых, вы всегда можете использовать библиотеку, которая использует трюк LD_PRELOAD . По сути, трюк LD_PRELOAD позволяет внедрять DLL, что означает, что можно создавать инструменты, которые помогут отслеживать использование памяти в вашем приложении без каких-либо изменений. Инструменты, такие как dmalloc и efence , довольно обширны в предлагаемых ими средствах отладки.

Наконец, последние выпуски GCC включали инструмент под названием Mudflap . В основном это использует инструментарий функций для обертывания вызовов вокруг тех же функций памяти, что и dmalloc, efence и Valgrind. Программа будет заметно медленнее и может быть настроена во время выполнения, хотя, похоже, у нее большой потенциал.

Я использовал все три и нашел Вальгринда очень полезным. Я также был очень заинтересован в использовании Mudflap, хотя пока не смог.

15 голосов
/ 20 ноября 2009

Вы должны взглянуть на " кросс-платформенный детектор утечки памяти ", очень похож на технику crtdbg.h

9 голосов
/ 19 ноября 2009

Вы также можете найти полезной переменную среды MALLOC_CHECK_.

Из справочной страницы malloc (3):

Последние версии Linux libc (позже 5.4.23) и glibc (2.x) включают реализацию malloc (), которая настраивается с помощью переменных среды. Когда задано значение MALLOC_CHECK_, используется специальная (менее эффективная) реализация, предназначенная для обеспечения устойчивости к простым ошибкам, таким как двойные вызовы free () с одним и тем же аргументом, или переполнению одного байта (ошибки от одного к одному) ). Однако не все такие ошибки могут быть защищены от утечек памяти. Если MALLOC_CHECK_ установлен в 0, любое обнаруженное повреждение кучи молча игнорируется; если установлено значение 1, диагностическое сообщение печатается на stderr; если установлено значение 2, abort (3) вызывается немедленно; если установлено значение 3, диагностическое сообщение выводится на stderr, и программа прерывается. Использование ненулевого значения MALLOC_CHECK_ может быть полезно, потому что в противном случае сбой может произойти намного позже, и тогда будет очень трудно отследить истинную причину проблемы.

4 голосов
/ 19 ноября 2009

Возможно, вы могли бы использовать Boehm сборщик мусора в качестве инструмента обнаружения утечек:

http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html

С сайта:

#include "leak_detector.h"

main() {
    int *p[10];
    int i;
    /* GC_find_leak = 1; for new collector versions not     */
    /* compiled with -DFIND_LEAK.               */
    for (i = 0; i < 10; ++i) {
    p[i] = malloc(sizeof(int)+i);
    }
    for (i = 1; i < 10; ++i) {
    free(p[i]);
    }
    for (i = 0; i < 9; ++i) {
    p[i] = malloc(sizeof(int)+i);
    }
    CHECK_LEAKS();
}   

(вы получаете уведомление через stderr)

3 голосов
/ 19 ноября 2009

У меня была такая же проблема, когда мы начали портировать на Mac. «Запуск с инструментом повышения производительности -> утечки» был единственным, что я нашел, и я менее чем взволнован этим ... по крайней мере по сравнению с CRTDEBUG. Я понимаю, что есть некоторые варианты (как описано здесь другими), но в конечном итоге, поскольку мы многоплатформенны, мы используем Windows для поиска утечек.

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

.
3 голосов
/ 19 ноября 2009

Я не знаю ничего «встроенного», которое бы делало то, что вы описываете, но не похоже, что было бы очень трудно «свернуть свою» версию этого. Вы просто хотите, чтобы ваш новый отладчик записывал указатель, файл и строку в map<void*, AllocationInfo>, где ключ - это выделенный указатель, а значение (AllocationInfo) будет некоторой структурой, которая содержит имя файла, номер строки и т. Д. Вы также необходимо определить пользовательский оператор удаления, который проверяет карту на предмет удаления указателя. Если найдено, эта запись будет удалена с карты. Затем во время остановки процесса вы создаете содержимое карты.

Я нашел страницу, где кто-то описывает свою собственную доморощенную систему, которая работает следующим образом .

...