Открыть список
Как стать автором
Обновить

Комментарии 45

непонятно какая платформа имеется ввиду и какой компилятор в разделе «Час расплаты». Может вы подразумеваете наличие одной платформы, одной ОС и одного компилятора? тогда поделитесь пожалуйста, а то я мож отстаю от времени.

По поводу предложеного метода, думаю не очень пригоден для больших проектов, предпочитаю Valgrind для отладки и «умные указатели» в качестве реализации, естественно где это уместно и оправдано.
Спасибо за замечание; при тестировании использовалось MSVC9 на Vista SP2. Тот же порядок (но немного бОльшие цифры) выходят для тестового приложения запущенного на XP SP3. «Час расплаты» целиком относится только к Win32.

Да, для больших (хотя это понятие для каждого своё) проектов этот метод не пригоден, согласен. А «умные указатели» тоже не стоит воспринимать как панацею, от «лишнего» add reference они не застрахованы (человеческий фактор), а найти его иногда крайне сложно (а, интересно, Valgrind справится? особенно меня интересует эта проблема для CComPtr).
CComPtr никогда не пользовался и не представляю как он устроен. Но полюбому поможет, так как память выделяет и освобождает сам Valgrind (я незнаю работает ли он с визуалстудией или ему нужен обязаельно POSIX, но мне кажется, что ему нужен POSIX и для Visual Stusio он получается непригоден, но не уверен),

Вообще есть автоматиеские указатели, которы разрушают объект, когда последний из указателей выходит за область видимости. Много есть инструментов в Boost, Qt и новой спецификации С++. Могу сказать только про Qt, так как глубоко разбирался только с ними, при правильном подходе — можно спастить практически полностью от человеческого фактора.
Если взять за практику такой порядок, когда объект сам прибирает за своими детьми, то потребность в ручных delete сократится почти до нуля. Но тем не менее даже в этом случае бывают очень странные утечки %).
>Вообще есть автоматиеские указатели, которы разрушают объект, когда последний из указателей выходит за область видимости.
Это если в памяти не висит какой-то объект, который вроде бы и в зоне видимости находится, но нафиг уже не нужен в общем то. Часто же и такое бывает. А тут ни какие анализаторы, вообще ничего не поможет, кроме владения ситуацией
Был уверен, что Debug-конфигурация проекта делает это самостоятельно. По крайней мере, в MSVS6.0 после смерти программы можно было посмотреть output и увидеть, кто где выделил и не собрал.

А по поводу сборщиков мусора — фиг его знает, не определился: консервативные сборщики мусора — г##но в случае c с++, более агрессивные сканирующие — опасно, могут номер телефона в данных принять за ненужный указатель и «убрать».
Да, в VC6 утечки выводились автоматически, поскольку по умолчанию был установлен флаг _CRTDBG_LEAK_CHECK_DF. С семерки — нет, но его можно включить через _CrtSetDbgFlag(). Ну или явно использовать _CrtDumpMemoryLeaks() (в действительности, оно и звалось перед выходом из main() ).
Valgrind вам в руки. Или, на худой конец, google heap checker.
Google heap checker насколько я понял только под Linux. А вообще, насколько бы ни были хороши внешние инструменты, тут рассматривается несколько другая задача — можно назвать это самодиагностикой. Отдав программу на предрелизное тестирование, например, мы убедимся, что у программы нет серьезных утечек. А если вдруг есть, то и поймем — где они. Главное, тестеров не придется учить новым штукам. Для маленьких проектов это актуально.
Обернуть запускальник в валгринд, и пусть тестируют полным циклом. Лог залить девам. Зачем учить новому?
полностью согласен!
Аналогичными define-ами можно обернуть открытие/закрытие сокетов, файловых дескрипторов и еще разных ресурсов выделение. Но вообще валгринд отлично все ловит, заодно детектит некорректые чтения/записи, неициализированные данные, если, конечно программа с ним совместима.
В данном случае необходимость переопределения new имеет исторические корни, не в этом смысл. А Debug CRT тоже имеет средства обнаружения неициализированных данных (и обращений к уже освобожденным), выходов за границы массива. В сочетании с AppVerifier можно обрабатывать и попытки чтения/записи по неверным адресам. А вообще, Windows-программисты тоже должны как-то жить :)
Да, валгринд то не работает под виндос. Специально посмотрел. Думаю для С++ виндос прогерам довольно занятный пост.
для винды есть С№
С++ — для настоящих мужчин!
я все меньше и меньше встречаю приложений на С++ под винду
«Dmalloc is not as good with C++ as C...» из их онлайн документации. И объясните тогда пожалуйста, чем dmalloc «лучше» debug CRT?
НЛО прилетело и опубликовало эту надпись здесь
Можно дебагать уже собранные поделия. Но вообще это все фигня, валгринд рулит :)
Ну это не совсем честное сравнение. Фактически, в том посте рассматривается ситуация, когда выделяется множество динамических объектов небольшого размера, а затем все они убиваются за раз.

В таких случаях вообще можно порекомендовать какой-нибудь boost::pool и не париться.

В общем же случае, конечно, сборщик мусора снижает производительность, потому что это некоторый нетривиальный алгоритм, требующий времени на выполнение, я так понимаю. А хуже всего то, что он может вызвать неравномерность выполнения: 30 секунд полёт нормальный, потом он решил почистить память — и 30 секунд ещё висим.
Субъективно очень даже снижает. Вообще надо бы взяться и оттестить, а то тезис
>Он, оказывается, работает быстрее, чем ручные delete. Раза в полтора.
немного удивляет и, быть может, подвох в чем-то другом.
статья «люди, не надо писать правильно на с++ и придумывать „костыли/велосипеды“! Используйте true дебаг тулзы!»
НЛО прилетело и опубликовало эту надпись здесь
могу обе руки дать, что в моем коде они есть. Специально оставил, что в будущем «покопаться» :)
читаем саттера и учимся писать без ашипок…
это я про то, что (цитата из статьи которую комментируем)
Не допускать ситуации вроде бы и не трудно — воспользуемся правилом «класть на место всё что взяли», но на практике это сильно осложняется человеческим фактором (банальная невнимательность), хитростью архитектуры и нелинейным порядком выполнения операторов, например, из-за применения исключений.

это не только не трудно, но большей частью абсолютно не накладно для рабочего кода. А уж исключения то просто обязаны заставлять вас писать ПРАВИЛЬНО, а не использовать дебаг тулзы для поиска мест «где же я еще прокосячил»
НЛО прилетело и опубликовало эту надпись здесь
я лишь заметил общий тон статьи, а не самоувернно заявлял что я пишу без ошибок. Не надо читать между строк особенно того что я не писал вообще.
Должен, однако, предупредить, что _CrtDumpMemoryLeaks может и врать. В проекте, над которым я сейчас работаю, он выдаёт дамп в сотни тысяч строк, тогда как сторонний полноценный профайлер выдаёт гораздо меньше утечек, и те большей частью в реализации строк в MFC/ATL. При этом отмечу, что студия не находит место выделения памяти в исходниках при клике на строках дампа, созданного функцией _CrtDumpMemoryLeaks.
_CrtDumpMemoryLeaks может врать только в одном ключе — он пропускает объекты выделенные вручную через HeapAlloc, GlobalAlloc. Как отсечь глобальные и статические объекты я написал, и да, их использованием MFC, увы, славится. Строку и имя файла определяет, если переопределить new, но «прыгать» по ней не будет. Но и время анализа и исправления утечки обычно больше, чем навигации по коду, всё-таки.
Да нет, врать он и по-другому умеет — сообщает о несуществующих утечках, и никакой ссылки на место в исходниках не выдаёт. просто пишет «утекло столько-то байтов» и дампит кусочек памяти. Как раз отсутствие таких ссылок и является одной из причин считать эти утечки ложными. Другая причина — сторонний профайлер ничего о них не сообщает.
Всегда пользовался AQTime'ом, гораздо проще и пока ни разу не подводил. И ему можно верить, сервер работает месяцами — никаких ликов не обнаружено.
Недопонял, как эту фишку можно поюзать, скажем, в готовом проекте, во время выполнения которого все время в памяти находится большое число связанных объектов (например, 3д игрушка с физикой — там будет куча моделек, текстур, сущностей, связанных между собой и взаимодействующих с их физическими моделями). Я так понял, что эта фича позволяет снять дамп памяти, в котором каждый объект несет информацию о том, где он был аллоцирован. Но как это поможет, если мы не в состоянии отделить зерна от плевел, т.е. объекты, которые должны быть живы, от тех, которые должны были быть уничтожены на момент снятия дампа?
Это реализуется при помощи _CrtMemCheckpoint, _CrtMemDumpAllObjectsSince (про это было) и _CrtMemDifference, про которую не упомянул, наверное зря.

А вообще идеология простая, перед открытием проекта/сцены/модели делаем _CrtMemCheckpoint, после закрытия — _CrtMemDumpAllObjectsSince. Все новосозданные и не удаленные объекты являются подозрительными на утечку (но не обязаны ей быть).
Ага, я невнимателен, спасибо.
//
Жаль только, что можно работать только с одним, глобальным пулом памяти. Было бы здорово научиться выделять для различных групп объектов различные пулы памяти (прописывать имена пулов в классах), и затем сравнивать состояния в контрольных точках конкретных пулов. Это, мне кажется, упростило бы локализацию утечек.
И это тоже возможно средствами debug CRT, за счет более хитрого переопределения new. От способа веет «велосипедностью», и я боюсь, что любители внешних анализаторов совсем разозлятся — но, если кому-то интересно, могу рассказать, как это делается.
Расскажите в двух словах без деталей, если не трудно.
Мне приходит в голову либо добавить в структуру, оборачивающую выделенную память, свое собственное поле, в котором хранить ID пула, и задать макрос new для каждой группы классов, которые будут использовать этот пул. Это навряд ли получится, так как структура внутренняя.
Либо переопределить глобальный оператор new и уже с указателем, полученным из alloc'a, связать информацию о пуле. Соответственно, при выводе информации об утечках нужно каким-то способом прицепить туда эту информацию, выводя статистику по нужным пулам, или группируя.
ответ по птатформе: это Вин32
для никс платформы что либо лучшее валгринда найти тяжело
для макоси — есть cвой анализатор, для солярки свой (признаюсь с соляркой не работал, но на Конференции SunTechDays долго общался на тему утечек с разработчиками OpenSolaris)

но если подойти к программированию теоретически, то есть пара простых правил по работе с выделением памяти:
выделение ресурса, в том числе памяти — делается в конструкторе, освобождение в деструкторе.
Используем «умные» (интеллектуальные) указатели.
если соблюдаем правила, то, как правило, утечек не бывает. Хотя, пройтись валгриндом по приложению — святое дело.
Под макосью, кстати, валгринд работает, но отладчик аттачить не умеет, к сожалению :(
с ними (утечками) не надо бороться
их надо — не допускать!
Вы, видимо, прочитали только заголовок.
да нет, сама статья мне понравилась тоже
просто утечки надо не допускать, не знаю почему такая нервная реакция у минусеров :)
Мне кажется, что лучше бы сделали обзор всевозможных утилит и фреймворков для нахождения и локализации утечек памяти. CRT'шными функциями пользоваться умеют почти все, а для тех, кто ещё не умеет, всё понятно расписанно в мсдне. Да и CRT это однобоко в сторону винды, а как же быть тем, кто пишет под BSD например?
это верно,
нам остается использовать BSD-шные утилиты,
это было в моих комментах, за что и минуснули.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.