Глава 15.2 Обнаружение утечек памяти и других ошибок
January 22nd, 2010 Begemot Posted in Учебники
Перевод медленно но движется. Выкладываю вторую часть 15 главы – про поиск утечек памяти используя возможности wxWidgets.
Если кто хочет помочь в переводе оставшихся глав – вы всегда можете поучаствовать и внести свой вклад, мы будем рады 🙂 Вся информация собрана на странице посвященной переводу книги по wxWidgets. Так что дерзайте:) Только согласовывайте свои намеренья до начала перевода, что бы не работать зря…
Глава 15.2 Обнаружение утечек памяти и других ошибок
В идеальном случае, когда ваше приложение завершает работу, все объекты должны быть корректно удалены либо самим приложением, либо библиотекой wxWidgets. Вы не должны оставлять не удаленной использованную память, даже не смотря на то что операционная система и освободит ее автоматически вместо вас после завершения программы. Не смотря на искушение махнуть рукой на очистку объектов, вам действительно стоит добиваться очистки всего того что вы создали. Часто подобные утечки памяти это симптомы проблем с вашим кодом, которые могут привести к потерям больших объемов памяти во время работы программы. Подобные проблемы значительно труднее обнаружить спустя некоторое время после написания проблемного кода, так что постарайтесь привыкнуть никогда не оставлять в программе даже малейших утечек памяти.
Как же проверить есть ли в вашей программе утечки памяти? Вы можете найти различные внешние решения для обнаружения подобных проблем (memory-checking tools). Плюс сама библиотека предоставляет простой встроенный механизм проверки. Для его использования в отладочной конфигурации вашего проекта, установите ряд опций в файле setup.h (Windows) или изменить опции сборки (для других платформ или CGG для Windows).
Опции файла setup.h:
#define wxUSE_DEBUG_CONTEXT 1
#define wxUSE_MEMORY_TRACING 1
#define wxUSE_GLOBAL_MEMORY_OPERATORS 1
#define wxUSE_DEBUG_NEW_ALWAYS 1
используйте следующие ключи при компиляции:
–enable-debug –enable-mem_tracing –enable-debug_cntxt
Правда данный механизм имеет ряд ограничений: он не работает с MinGW и Cygwin (по крайней мере, на момент написания книги), а также не можете использовать wxUSE_DEBUG_NEW_ALWAYS, если вы используете STL или компилятор CodeWarrior.
При включенном wxUSE_DEBUG_NEW_ALWAYS, все встречающиеся операторы new как в самой wxWidgets, так и в вашем коде будут переопределены как new(__TFILE__,__LINE__), что приведет использованию специальных процедур для выделения и освобождения памяти. Также вы можете явно использовать эту версию оператора, просто вызывая WXDEBUG_NEW вместо обычного оператора new.
Самый простой способ использовать системы обнаружения утечек памяти – просто не делать ничего специального:) Запустите программу под управлением отладчика и закройте ее, дебагер сам сообщит вам об обнаруженных ошибках, например вот так:
There were memory leaks. (найдены утечки памяти)
– Memory dump –
.\memcheck.cpp(89): wxBrush at 0xBE44B8, size 12
..\..\src\msw\brush.cpp(233): non-object data at 0xBE55A8, size 44
.\memcheck.cpp(90): wxBitmap at 0xBE5088, size 12
..\..\src\msw\bitmap.cpp(524): non-object data at 0xBE6FB8, size 52
.\memcheck.cpp(93): non-object data at 0xBB8410, size 1000
.\memcheck.cpp(95): non-object data at 0xBE6F58, size 4
.\memcheck.cpp(98): non-object data at 0xBE6EF8, size 8– Memory statistics –
1 objects of class wxBitmap, total size 12
5 objects of class nonobject, total size 1108
1 objects of class wxBrush, total size 12Number of object items: 2
Number of non-object items: 5
Total allocated size: 1132
Этот отчет говорит нам о том, что были созданы, но не были освобождены wxBrush, wxBitmap и еще один объект, неизвестного библиотеке класса (объект не содержит информации о типе). В некоторых средах разработки вы можете быстро перейти к строке кода, содержащей выделение памяти, всего лишь дважды кликнув на сообщение об ошибке. Эта замечательная возможность позволяет вам всего в один шаг перейти к проблемному месту. Для более легкого поиска ошибок, всегда добавляйте информацию времени выполнения (RTTI) к любому классу наследнику wxObject. Просто добавьте DECLARE_CLASS(class) в определенеи класса и IMPLEMENT_CLASS(class, parentClass) в любом месте файла реализации.
Вышеописанная система слежения за памятью, также пытается отловить попытки перезаписи и ошибки удаления ранее удаленного блока. Функции, отвечающие за выделение и освобождение памяти, ставят специальные пометки для "хороших" и для удаленных блоков памяти. Как только приложение попробует удалить блок памяти без соответствующей метки, вы сразу получите сообщение о проблеме. То же самое произойдет и при попытке удалить блок помеченный как уже удаленный. Это облегчает обнаружение проблем, связанных с порчей памяти.
Используя статические методы класса wxDebugContext, вы можете получить листинг текущих объектов в памяти (PrintClasses) или показать количество объектов и не-объектов (тех, которые не имеет информации времени выполнения (wxWidgets RTTI information)) вызвав PrintStatistics. Используя SetCheckpoint, вы можете установить, своего рода, контрольную точку после чего wxDebugContext будет выводить информацию об объектах выделенных после нее, игнорируя ранее созданные объекты. Более подробную информацию можно получить из справки по классу wxDebugContext и исходного кода примера samples/memcheck.
Вместо использования базовой системы обнаружения утечек, которую дает вам wxWidgets, вы можете использовать коммерческие продукты такие как BoundsChecker, Purify или AQtime. Или бесплатные альтернативы StackWalker, ValGrind, Electric Fence или MMGR от Fluid Studios. Если вы пользуетесь Visual C++, wxWidgets использует стандартный для этого компилятора механизм обнаружение ошибок, который не показывает вам имя класса, но зато сообщает номер строки кода. Убедитесь, что wxUSE_DEBUG_NEW_ALWAYS установлен в 1 в setup.h. Так как он переопределяет new, вам может понадобится отключить этот механизм, если вы заметите проблемы с другими библиотеками.
February 24th, 2010 at 12:57 pm
Добрый день.
Подскажите, пожалуйста, имеет ли wxWidgets средства проверки факта выделения памяти под указатель. Для полной ясности, пишу библиотеку, которая принимает указатель извне. Мне надо выяснить проинициализирован ли он и какой объем памяти под него выделен. Знаю, что в MFC есть подобные функции (IsBadWritePtr и IsBadReadPtr)
Заранее благодарен
February 24th, 2010 at 1:15 pm
Только что посмотрел документацию – IsBadWritePtr и IsBadReadPtr, это WinAPI функции, а не MFC, соответственно их можно использовать без проблем, но конечно только под виндой.
Насчет родных wxWidgets функций, незнаю.
February 24th, 2010 at 2:27 pm
Спасибо