Выбрать главу
Детекторы утечки памяти

На рынке имеется ряд продуктов, которые на основе различных стратегий обнаруживают утечки памяти в приложениях. Утечка памяти -- это то, что случается, когда программа запрашивает блок памяти из кучи (используя, например, malloc() в Cи под UNIX или DOS , или оператор new в C++), а затем забывает вернуть его обратно по своему завершению. Иногда это приводит к нарушению работы других процессов, работающих на той же платформе, поскольку некоторые операционные системы позволяют одному процессу захватить всю имеющуюся память системы и файл подкачки.

Даже если операционная система достаточно разумна, чтобы ограничить выделяемую отдельному процессу память, приложение может вскоре исчерпать свою квоту, что обычно заканчивается сбоем с точки зрения пользователя.

Поэтому утечки памяти -- это Плохая Вещь.

Это причина того, почему люди продают, и покупают, детекторы утечки памяти. Неприятность в том, что утечки -- это симптом проблемы, а не причина проблемы. Не так трудно вызвать free() или удалить объекты, которые больше не нужны. Применение delete к коллекции указателей на активные объекты -- вот опасное занятие, как и перезаписывание их адресов. Что если эти объекты, скажем, зарегистрировали функции обратного вызова (callbacks) в GUI ? Как же их освободить? Деструкторы вне контроля -- это программист вне контроля. Если программист не может продемонстрировать контроль над объектами, которого достаточно для избежания утечек памяти, то как мы можем думать, что правильно еще хоть что-нибудь?

Концептуальная целостность -- это одна из самых сильных подпорок в сохранении контроля над объектами. Полезное общее правило (хотя, как и все правила, не всегда применимое) должно говорить, что уровень, который конструирует модуль, должен отвечать за его уничтожение. Это, по крайней мере, фокусирует внимание на жизненном цикле объектов, а не на всего лишь нескольких аспектах их поведения, которые можно проследить на диаграммах использования.

Таймауты

Один из наиболее эффективных способов получения "затравки" для генератора случайных чисел -- посмотреть на системные часы. Аналогично, если два процесса работают на одном и том же процессоре, то мы никогда не сможем предсказать, сколько времени пройдет от запуска программы до достижения заданной точки в программе. Мы не можем даже точно предсказать, сколько процессорного времени будет выделено каждому процессу.

Таким образом, таймауты -- это Плохая Вещь. Есть мнение, что они значительно увеличивают пространство состояний системы, что делает поведение системы гораздо хуже предсказуемым для проектировщика. При отладке они могут привести к условиям, при которых невозможно будет воспроизвести сбой. Не используйте их, кроме тех случаев, когда они абсолютно необходимы.

Коммуникационные уровни часто обязаны использовать таймауты, поскольку когда приходит время их работы, единственный способ обнаружить, что удаленное устройство готово к взаимодействию -- послать ему сообщение и дождаться, посылает ли оно ответ. Как долго нужно ждать? "Проблема Византийских полководцев" (`Byzantine Generals' Problem') это иллюстрирует. Поэтому в большинстве современных систем есть таймауты на уровне коммуникации, но нет никакого оправдания использовать их повсюду, и там, где они должны использоваться, они должны быть сокрыты внутри инкапсулирующего объекта, который для целей отладки может быть заменен на детерминированный генератор событий (например, нажатие клавиши).

Проектируй для тестирования

Редко бывает достаточно, что наши системы работают. Обычно нам также нужно знать, что они работают хорошо. Это положение может показаться тривиальным, но из него есть следствия для того, как нам организовать свою работу.

На уровне выявления требований мы можем обследовать определенный участок проблемной области, который, как мы предполагаем, может стать источником проблем, даже не зная, собрали ли мы всю относящуюся к проблеме информацию. Для повышения уверенности, что мы ничего не упустили, нам нужно пристально посмотреть пошире, чтобы увидеть, куда что уходит, и откуда что приходит. Мы должны найти способ представления этих потоков, чтобы можно было охватить одним взглядом большую картину. Стопки прозы или толстые папки Диаграмм Потоков Данных здесь совсем не помогут (хотя они могут пригодиться где-то в другом месте проекта), поскольку они не позволят нам увидеть одним взглядом, что нет потерянных концов. Если мы можем убедиться, что нет потерянных концов, то мы с основанием можем быть уверены, что здесь нет скрытых ужасов, которые мы обнаружим во время реализации. Это пример технологии картостроителя для очерчивания проблемы.