Microsoft Windows 7

Рекомендации по улучшению стабильности приложений

Алексей Федоров

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

В настоящем цикле статей мы приведем ряд рекомендаций по улучшению стабильности приложений. Мы познакомимся с техникой, позволяющей избежать утечек памяти и предотвратить зависание приложений, а также обсудим использование механизма Application Restart and Recovery, обеспечивающего перезапуск приложений, которые или заблокировали какие-либо ресурсы, или перестали реагировать на сообщения системы и механизма Windows Error Reporting, позволяющего собирать данные о сбоях, происходящих в приложениях.

Утечки памяти — это класс ошибок в коде приложений, в результате которых приложение не освобождает ранее занятую память. Из-за утечек памяти может снижаться производительность как приложения, так и самой операционной системы — блокирование больших фрагментов памяти приводит к более интенсивному использованию механизма постраничной виртуализации памяти на жестком диске, что является более медленной операцией по сравнению с работой непосредственно с оперативной памятью. По завершении работы приложения Windows освобождает всю занятую процессом память, так что приложения, которые выполняются за короткое время, не могут заметно повлиять на производительность системы. Проблемы возникают с процессами и приложениями, которые выполняются длительное время, например такими, как расширения для Windows Explorer, — утечки памяти в этом случае могут привести к существенному снижению производительности системы и, как следствие, к необходимости перезагрузки системы для восстановления ее нормальной работоспособности или перезагрузки самих приложений, если они поддерживают такую возможность, но об этом далее.

Существует несколько способов выделения блоков памяти в приложении. Каждый способ может привести к утечке памяти в том случае, если ранее выделенная память не будет своевременно освобождена. Приведем несколько примеров корректного использования функций выделения памяти:

  • выделение области «кучи» (heap) через функцию HeapAlloc() или ее эквиваленты для библиотеки языка С++ malloc или new. Для освобождения памяти следует применять «парные» функции HeapFree(), free() и delete(). Отметим, что начиная с Windows Vista автоматически поддерживается так называемая низкофрагментированная «куча», использование которой позволяет снизить фрагментацию «кучи» — состояние, при котором в «куче» достаточно памяти для удовлетворения запроса на выделение памяти, но нет последовательной области необходимой длины;
  • прямое выделение памяти через функцию VirtualAlloc(). Для освобождения памяти, выделенной таким способом, следует применять функцию VirtualFree();
  • использование ссылок (handle), полученных через функции CreateFile(), CreateEvent(), CreateThread(). Освобождение памяти осуществляется с помощью функции CloseHandle(), которой в качестве одного из параметров передается полученная одной из перечисленных ранее функций Create…() ссылка;
  • применение ссылок, полученных через соответствующие функции подсистем USER и GDI. По умолчанию каждому процессу выделяется квота на 10 тыс. ссылок. Для каждой конкретной функции существует «парная» функция, освобождающая занятую память, — подробнее см. в документации к Windows SDK.

Для обнаружения утечек памяти нужно следить за поведением приложения с течением времени. Это можно делать с помощью Windows Task Manager — следует добавить к списку отображаемых колонок колонки Memory-Commit Size, Handles, User Objects и GDI Objects. Это позволит вам определить точку отсчета в потреблении ресурсов вашим приложением (рис. 1).

 

Рисунок

Рис. 1. Task Manager

Для более детального изучения работы приложения и упрощения определения проблем с утечкой памяти необходимо использовать специализированные средства, предоставляемые компанией Microsoft. К ним относятся:

  • средства мониторинга, входящие в состав Windows 7, — Performance Monitor и Resource Monitor (рис. 2 и 3);

 

Рисунок

Рис. 2. Performance Monitor

Рисунок

Рис. 3. Resource Monitor

  • средство тестирования приложений Application Verifier (рис. 4);

 

Рисунок

Рис. 4. Application Verifier

  • для анализа выделения областей памяти в «куче» следует применять утилиту UMDH, входящую в состав Debugging Tools for Windows;
  • утилита XPerf также позволяет трассировать выделение памяти в «куче».

Для того чтобы ваши приложения корректно работали с ресурсами системы, в первую очередь с памятью, следует придерживаться следующих правил:

в коде на С++ используйте smart pointers — шаблонные классы, имитирующие обычные указатели с возможностью очистки, освобождения памяти, проверки границ и тому подобного для выделения памяти как в «куче», так и для получения ресурсов Win32, включая ссылки. Библиотека C++ Standard Library содержит класс auto_ptr (описан в <memory>), который можно использовать для выделения памяти в «куче». В состав библиотеки ATL входит большое число классов для автоматического управления ресурсами на уровне как объектов «кучи», так и ресурсов Win32;

  • применяйте встроенные функции компилятора, например _com_ptr_t для преобразования указателей на COM-интерфейсы в smart pointers и упрощения подсчета ссылок (reference). Для других COM-типов также существуют схожие классы — например _bstr_t и _variant_yt;
  • следите за применением памяти в коде на .NET. Обратите внимание на то, что код на .NET также подвержен утечкам памяти — это происходит из-за того, что сборщик мусора (garbage collector) не освобождает память до тех пор, пока существуют ссылки на нее;
  • в веб-приложениях утечки памяти могут возникать из-за циклических ссылок между COM-объектами и кодом на JScript. Internet Explorer 8, входящий в состав Windows 7, позволяет решить большинство проблем, связанных с такими утечками памяти. Для предыдущих версий браузера следует использовать специальное отладочное средство — JavaScript Memory Leak Detector;
  • старайтесь не применять несколько вариантов завершения работы функции. Все выделения памяти, присвоенные переменным в области действия функции, должны быть освобождены перед ее завершением, желательно в одном блоке кода, доступном всегда независимо от поведения функции;
  • не используйте исключения без предварительного освобождения памяти, занятой всеми локальными переменными в области действия функции. В случае применения стандартных исключений предусмотрите освобождение памяти в блоке __finally. Если используются исключения С++, все выделения памяти в «куче» и получение ссылок должны производиться через smart pointers;
  • не забывайте вызывать функцию PropVariantClear() перед удалением или повторной инициализацией объекта PROPVARIANT.

Итак, мы рассмотрели основные причины появления утечек памяти, а также привели рекомендации по корректному выделению памяти и ресурсов Windows, включая рекомендации для кода на С/С++, управляемого кода и клиентского кода веб-приложений.

***

Следующая тема, которая имеет непосредственное отношение к стабильности как приложений, так и самой системы, — это зависание приложений. Ее мы рассмотрим в следующей статье данного цикла.

 

В начало В начало

КомпьютерПресс 10'2009

Наш канал на Youtube

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует