Ответ 1
Вы должны взглянуть на Кросс-платформенный детектор утечки памяти", выглядит очень похоже на технику crtdbg.h.
После многих лет работы над библиотекой С++ общего назначения с использованием компилятора 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, и я изучил некоторые инструменты выделения/утечки (например, инструменты и MallocDebug), но я признаю, что не потратил времени, чтобы полностью окунуться в них. Я все время откладываю на то, что на самом деле мне нужно указать, что я ищу утечку раньше времени, вместо того, чтобы автоматически получать уведомление об этом.
Я использую Xcode 3.2, и я слышу, что теперь есть отличная интеграция со средством статического анализа, но опять же я не рассматривал это. Я ищу какое-то представление о моих вариантах. Есть ли сопоставимый механизм, встроенный в GCC и/или Xcode? Есть ли простая сторонняя библиотека или инструмент, который выполняет те самые основные функции, которые я знаю и люблю? Или я должен сосать его и узнать новый способ делать что-то?
Вы должны взглянуть на Кросс-платформенный детектор утечки памяти", выглядит очень похоже на технику crtdbg.h.
У вас есть несколько доступных вам вариантов.
Во-первых, и наиболее популярно вы можете запускать свое приложение под такими инструментами, как Valgrind. Это должно указывать на ряд нарушений памяти, таких как чтение и запись указателей NULL, а также утечки памяти. В наборе Valgrind имеется ряд инструментов, поэтому обязательно проверьте их.
Во-вторых, вы всегда можете использовать библиотеку, которая использует трюк LD_PRELOAD. В принципе, трюк LD_PRELOAD позволяет использовать DLL-инъекцию, а это значит, что инструменты могут быть созданы, чтобы отслеживать использование вашей памяти в приложении без каких-либо изменений. Вы найдете такие инструменты, как dmalloc и efence, чтобы быть достаточно обширными в средствах для отладки, которые они предлагают.
Наконец, последние выпуски GCC включали инструмент Mudflap. Это в основном использует функцию инструментария для обертывания вызовов вокруг одних и тех же функций памяти, которые dmalloc, efence и Valgrind. Программа будет заметно медленнее и может быть настроена во время выполнения, хотя по-прежнему выглядит так, что у нее большой потенциал.
Я использовал все три и нашел Valgrind очень полезным. Мне также очень хотелось использовать Mudflap, хотя я еще не смог.
Вы также можете найти полезную переменную среды MALLOC_CHECK_.
Из справочной страницы malloc (3):
Последние версии Linux libc (позже 5.4.23) и glibc (2.x) включают реализацию malloc(), которая настраивается через переменные среды. Когда установлен MALLOC_CHECK_, используется специальная (менее эффективная) реализация, которая предназначена для толерантности к простым ошибкам, таким как двойные вызовы free() с одним и тем же аргументом или переполнения одного байта (ошибки by-by-one). Тем не менее, не все такие ошибки могут быть защищены, и могут возникнуть утечки памяти. Если для параметра MALLOC_CHECK_ установлено значение 0, любое обнаруженное повреждение кучи тихо игнорируется; если установлено значение 1, на stderr выводится диагностическое сообщение; если установлено значение 2, то прерывание (3) вызывается немедленно; если установлено значение 3, диагностическое сообщение печатается на stderr, и программа прерывается. Использование ненулевого значения MALLOC_CHECK_ может быть полезно, поскольку в противном случае авария может произойти намного позже, и истинную причину проблемы тогда очень сложно отследить.
Возможно, вы можете использовать сборщик мусора 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)
Я не знаю ничего "встроенного", который делает то, что вы описываете, но похоже, что было бы очень сложно "перевернуть свою" версию. Вы просто хотите, чтобы ваша новая отладочная запись записывала указатель, файл и строку в map<void*, AllocationInfo>
, где ключ является выделенным указателем, а значение (AllocationInfo
) - это некоторая структура, которая содержит имя файла, номер строки и т.д. Вы также необходимо определить пользовательский оператор удаления, который проверяет карту для удаляемого указателя. Если найдено, эта запись удаляется с карты. Затем во время выключения процесса вы выбрасываете содержимое карты.
Я нашел страницу, где кто-то описывает свою собственную доморощенную систему, которая работает так.
У меня была такая же проблема, когда мы начали переносить на Mac. "Run with performance tool → Leaks" был единственным, что я нашел, и я менее взволнован этим... по крайней мере, по сравнению с CRTDEBUG. Я понимаю, что есть некоторые варианты (как описано здесь здесь), но в конце концов, поскольку мы являемся мультиплатформой, мы используем Windows для поиска утечек.
Так как вы упоминаете статический анализатор. Мы потратили некоторое время, пытаясь разобраться в горячем состоянии, чтобы запустить его, пока не обнаружили, что он только C, но не С++