Отладка приложений

         

Использование утилиты MemStress


Теперь самое время добавить немного стресса. Как ни странно, но он может играть и положительную роль. К сожалению, довести до этого состояния 32-разрядные приложения Windows в наши дни намного труднее, чем раньше. Приложения прежних 16-разрядных Windows (да еще и современной 16-разрядной подсистемы Windows 98) можно выполнять под управлением изящной программы STRESS.EXE, которая поставляется в составе SDK и позволяет вводить в приложение различного рода искажения. Например, такие, которые заставляют ее буквально "пожирать" дисковое пространство и динамическую память (heap) интерфейса графических устройств (Graphics Device Interface — GDI), а также усиленно использовать файловые дескрипторы. Программа имеет подходящую пиктограмму — изображение слона, идущего по натянутому канату.

Чтобы подвергнуть "стрессу" 32-разрядные приложения Windows, можно подключиться к системе распределения памяти DCRT-библиотеки и контролировать результаты (успехи или неудачи) ее операций. MemStress обеспечивает средства для усиленного распределения памяти в С/С++-приложениях. (Оставлю на усмотрение читателя написание кода, "съедающего" дисковую память.) Чтобы облегчить применение MemStress, я написал интерфейс (на языке Visual Basic), позволяющий точно задать условия отказов.

MemStress обеспечивает принудительное создание отказов в распределениях (памяти), основанных на различных критериях: для всех распределений, для каждого n-ого распределения, после распределения определенного числа байт, по запросам через каждые n байт, для всех распределений вне исходного файла и на конкретной строке в исходном файле. Кроме того, можно заставить MemStress выдавать на любом запросе распределения подсказку в виде панели сообщения, в которой спрашивается, хотите ли вы получить отказ в данном конкретном распределении. Можно также устанавливать флажки DCRT-библиотеки, которые желательным образом влияли бы на программу. MFC-программа MemStressDemo (проект которой поставляется на сопровождающем компакт-диске) позволяет экспериментировать с установкой различных опций пользовательского интерфейса (UI) MemStress и просматривать соответствующие результаты.


Работать с MemStress довольно просто. Включите в свой код заголовочный файл BUGSLAYERUTIL.H и вызовите макрос MEMSTRESSINIT с именем вашей программы. Чтобы прекратить подключение распределений памяти, используйте макрос MEMSTRESSTERMINATE. Во время прогонов программы можно инициировать и останавливать эти подключения сколько угодно раз.

Скомпилировав свою программу, запустите MemStress UI, нажмите кнопку Add Program и введите (с клавиатуры) то же самое имя, которое указано в макросе MEMSTRESSINIT. После выбора желательных опций отказов нажмите кнопку Save Settings For This Program, чтобы сохранить установки в файле MEMSTRESS.INI. Теперь можно запускать программу и следить за ее поведением при отказах в распределении памяти.

Применять MemStress следует аккуратно. Например, если потребовать, чтобы терпели неудачу все распределения, превышающие 100 байт, при условии, что в функции initinstance вашего MFC-приложения имеется макрос MEMSTRESSINIT, то можно будет заподозрить MFC в неспособности инициализировать свои объекты. Лучшие результаты вы получите, если ограничите область действия MemStress тестированием отдельных ключевых областей программы.

Большая часть кода MemStress занимается чтением и обработкой файла MEMSTRESS.INI, в котором хранятся все установки для индивидуальных программ. С точки зрения DCRT-библиотеки, наиболее важной функцией является обращение к функции _CrtSetAilocHook во время инициализации MemStress, потому что для обработки распределений памяти этот вызов устанавливает функцию AllocationHook. Если эта функция возвращает TRUE, то запрос распределения продолжается, а возврат FALSE означает, что DCRT-библиотека отклонила этот запрос. К обработке распределения со стороны DCRT-библиотеки имеется только одно твердое требование: если параметр nBiockUse задает тип блока _CRT_BLOCK, то hook-функция должна возвратить значение TRUE, что позволит распределять блоки этого типа.

Обработка распределения выполняется для функций распределения любого типа. Тип функции указан в ее первом параметре, для которого допустимы следующие значения: _HOOK_ALLOC, _HOOK_REALLOC и _HOOK_FREE).Если в своей функции обработки распределения AllocationHook указать тип _HOOK_FREE, то будет пропущен весь код, который определяет, должен ли запрос памяти передаваться или отклоняться. Для типов _HOOK_ALLOC и _HOOK_REALLOC функция AiiocationHook выполняет ряд if-операторов, чтобы определить, встретилось ли какое-нибудь из условий отказа в распределении. Если условие отказа встретилось, функция возвращает FALSE.



Содержание раздела