Скоро о ней снова заговорили. 28 и 29 октября на телевидении и в прессе сообщалось, что из-за неадекватной работы системы были потеряны двадцать жизней. Говорили, что в одном конкретном случае врачи скорой помощи по рации сообщили на базу, что прибыли на место назначения и спросили, почему владелец похоронного бюро прибыл раньше. Исполнительный директор службы ушел в отставку, была назначена следственная комиссия.
Служба скорой помощи после трагедии не сразу отказалась от компьютерной системы, а переключилась на гибридную модель - частично ручную, частично полагающуюся на систему. Согласно официальным отчетам:
Эта гибридная система действовала с переменным успехом с 27 октября 1992 г. до раннего утра 4 ноября. Однако после двух часов 4 ноября работа системы значительно замедлилась, вскоре после этого система вышла из строя совсем. Перезагрузка не смогла решить проблему. Управление и персонал вернулись к бумаге и телефонным звонкам.
Что привело систему к краху, так что ее не могли сохранить даже как дополнение к ручным операциям? Отчет определил несколько причин. Вот основная:
Следственная команда пришла к выводу, что крах системы был вызван незначительной ошибкой программного обеспечения. Программист XX ('XX' здесь и далее заменяет название компании, разрабатывающей программное обеспечение данной системы) тремя неделями раньше оставил в системе кусок программного кода, который, используя небольшой файл на сервере, записывал и не стирал информацию о выезде машины на вызов. Через три недели память переполнилась. Эта ошибка была вызвана беспечностью и отсутствием проверки качества программного кода. Такого рода неисправности вряд ли могут быть обнаружены обычным тестированием программистом или пользователем.
Читатель должен сам решить, какую программную ошибку стоит называть незначительной, особенно принимая во внимание последний комментарий о трудностях тестирования, который еще будет подробно обсуждаться ниже.
Для тех, кто все еще думает, что можно пользоваться несерьезным подходом, и для тех, кто относится к управлению памятью только как к проблеме реализации, двадцать жертв лондонской службы скорой помощи должны служить грустным напоминанием о серьезности рассматриваемой проблемы.
Восстановление памяти: проблемы
Если уйти от несерьезного подхода и его упрощающих допущений, то предстоит решить, как и когда восстанавливать память. Возникают две проблемы:
[x]. Обнаружение (detection). Как найти мертвые элементы?
[x]. Восстановление (reclamation). Как восстановить для повторного использования память, присоединенную к этим элементам?
Для каждой из этих задач можно искать решение на одном из двух возможных уровнях:
[x]. Реализации языка - компилятор и среда исполнения обеспечивают общую поддержку любому ПО, создаваемому на этом языке и в данной среде.
[x]. Приложения - приложение само решает возникающие проблемы.
В первом случае управление выделенной памятью происходит автоматически с помощью программно-аппаратных средств. Во втором случае каждый разработчик приложения должен позаботиться об этом сам.
Фактически, существует еще третий возможный уровень, нечто среднее между этими двумя, - фабрика компонентов. Функции управления памятью возлагаются на общецелевые повторно используемые классы библиотеки ОО-среды. Подобно уровню приложения, можно использовать только разрешенные конструкции языка программирования, не имея прямого доступа к аппаратуре и функциям операционной системы. Подобно уровню реализации языка, проблемы управления памятью решаются один раз и для всех приложений.
Даны две проблемы и три способа решения каждой, в итоге - шесть возможных вариантов. Только четыре из них имеют практический смысл. Рассмотрим их.
Удаление объектов, управляемое программистом
Одно популярное решение - обнаружение мертвых элементов возложить на разработчика программы, а восстановление памяти решать на уровне реализации языка.
Это простейшее решение для реализаторов языка: все, что от них требуется, - это ввести в язык примитив, скажем,
Это решение реализовано в не ОО-языках, таких как Pascal (
Такое решение особенно приветствуется в мире С-программистов, любящих полностью контролировать происходящее. Обычная реакция таких программистов на тезис о том, что Objective-C может давать преимущества, благодаря автоматическому восстановлению памяти, следующая:
Я говорю, НЕТ! Оставлять недостижимые объекты - ПЛОХОЙ СТИЛЬ ПРОГРАММИРОВАНИЯ. Если вы создаете объект, вы должны отвечать за его уничтожение, если вы им не пользуетесь. Разве мама не учила вас убирать свои игрушки после игры? (Послано Яном Стефенсоном (Ian Stephenson), 11 мая1993.)
Для серьезной разработки программ эта позиция не позволительна. Хорошие разработчики должны разрешать кому-либо другому играть со своими 'игрушками' по двум причинам: надежности и простоты разработки.
Проблема надежности
Допустим, разработчик управляет утилизацией объектов с помощью механизма
Такие ошибки приводят к проблеме висячих ссылок, - когда в одном из полей существующего объекта хранится ссылка на удаленный объект. Если система, после того как область памяти, занимаемая этим объектом, была утилизирована и использована для хранения другой информации, попытается использовать ссылку, то результатом будет крах программы или (еще хуже) ее ошибочное или неуправляемое поведение.
Этот тип ошибки известен, как источник появления самых частых и неприятных жучков в практике языка С и производных языков. Программисты боятся таких жучков из-за трудности обнаружения их
