Опубликован: 03.10.2011 | Уровень: для всех | Доступ: свободно | ВУЗ: Тверской государственный университет
Лекция 7:

Создание объектов и выполняемых систем

6.7. Управление памятью и сборка мусора

В ситуации, изображенной на последнем рисунке, ссылка, которая была присоединена к объекту (первый созданный объект), затем была отсоединена и присоединена к другому. Что, хотелось бы знать, случилось с первым объектом? Хотя этот частный пример (два последовательных создания create x с одним и тем же x) не реалистичен, полезное ссылочное пересоединение является общеупотребительным и может поднимать те же самые вопросы. В свое время мы будем изучать ссылочное присваивание, такое как x:= y, чей эффект отображен на рисунке:

 Ссылочное переприсваивание

Рис. 6.18. Ссылочное переприсваивание

Оператор разрывает старую связь и присоединяет x к объекту, к которому присоединен у. Что случится с "Объектом 1"? Поставим более общий вопрос: мы рассмотрели способы создания объектов, а как объект может быть удален (deleted)?

Так как могут быть другие ссылки, присоединенные к "первому созданному объекту" или "Объекту 1", вопрос представляет реальный интерес. Когда ссылка на объект удаляется, как в наших примерах, то что случается с объектом, если не остается никаких других ссылок на этот объект? Здесь нет тривиального ответа, поскольку выяснение того, остались ли ссылки на данный объект, требует глубокого изучения всей программы в целом и понимания процесса выполнения программы. Возможны три подхода: легкомысленный, ручной, автоматический.

При легкомысленном подходе проблема просто игнорируется, неиспользуемые объекты остаются в памяти. Как следствие, это может привести к неконтролируемому росту занятой памяти. Такие потери памяти неприемлемы для постоянно работающих систем, используемых в различных встроенных устройствах, — потеря памяти на вашем мобильном телефоне может привести к остановке его работы. Все это справедливо для любой системы, создающей большое число объектов, которые постепенно становятся ненужными для системы. Легкомысленный подход неприемлем для любой нетривиальной системы.

Ручной способ управления снабжает программиста явными средствами возвращения объектов в распоряжение операционной системы. Программисты C++ могут, например, перед присваиванием x:=у освободить память, выполнив оператор free (x), сигнализирующий, что объект не нужен программе, и операционная система может использовать по своему усмотрению память, занятую объектом.

Автоматический подход освобождает программиста, перекладывая эту работу на механизм, называемый "сборщиком мусора" (garbage collector), или коротко GC. На GC лежит ответственность возвращения недостижимых объектов. Сборка мусора выполняется как часть вашей программы. Более точно, она является частью системы периода выполнения (run time system)множества механизмов, обеспечивающих выполнение программ.

Думайте о программе, как о параде, который идет по городу с музыкой, лошадьми и прочим, и о GC — как о бригаде уборщиков, следующей тем же маршрутом в нескольких сотнях метров позади и эффективно убирающей мусор, оставляемый парадом.

Реализация С++ обычно предпочитает ручной подход (из-за проблем, связанных с системой типов языка), но другие современные языки программирования обычно применяют автоматическую модель, используя сложно устроенные GC. Это верно для Eiffel, но справедливо и для Java и для Net-языков, таких как C#. Есть два главных довода для доминирования такого подхода.

  • Удобство: включение в программу операций освобождения памяти значительно ее усложняет, поскольку необходимо выполнять интенсивные подсчеты, дабы убедиться, что данный объект стал бесполезным. При автоматическом подходе эти обязанности входят в задачу универсальной программы — GC, — доступной как часть реализации языка или надстройки над операционной системой.
  • Корректность: поскольку подсчеты числа ссылок — вещь тонкая, ручной подход является источником весьма неприятных ошибок, когда операция free применяется к объекту, на который все еще остается ссылка в какой-либо далекой части программы. Как результат, программа может в какой-то момент работать некорректно с фатальными ошибками и прерыванием выполнения. Общецелевые GC эти проблемы в состоянии решить профессионально и эффективно не только для одной конкретной программы, но для всех программ.

Единственный серьезный аргумент против автоматической сборки мусора состоит в возможной потери эффективности. Освобождение объектов в любом случае требует определенного времени (исключая легкомысленный подход). Существует обеспокоенность, что GC будет прерывать выполнение в ответственный момент. Сегодня технология GC достигла такого уровня, что она не требует прерывания на полный цикл сборки — мусор собирается понемногу в некоторые моменты времени. Как результат, для большинства приложений прерывания становятся незаметными. Единственное остающееся беспокойство связано с системами "реального времени", встраиваемыми, например, в транспортные или военные устройства, где отклик системы требуется на уровне миллисекунд или менее и где недопустимы никакие посторонние задержки. Такие системы требуют особого подхода и не могут использовать многие другие преимущества современного окружения, включая динамическое создание объектов и виртуальную память.

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

6.8. Выполнение системы

Заключительное следствие механизма создания состоит в том, что можно понять, как происходит процесс выполнения системы (программы в целом).

Все начинается со старта

Если понять, как создаются объекты, выполнение системы станет простой концепцией.

Определения: выполнение системы, корневой объект, корневой класс, корневая процедура создания
Выполнение системы состоит в создании экземпляра - корневого объекта, принадлежащего специальному классу системы, называемому корневым классом, - используя специальную процедуру создания этого класса, называемую корневой процедурой создания.

Достаточно, чтобы корневая процедура создания (будем называть ее просто корневая процедура) могла выполнять предписанные ей действия. Обычно она сама создает новые объекты и вызывает другие методы, которые могут в свою очередь делать то же самое, вызывая новые методы и создавая новые объекты, — так развивается процесс выполнения. Можно думать о нашей системе — множестве классов, как о множестве шаров на бильярдном столе. Корневая процедура наносит удар по первому шару, который бьет другие шары, которые, в свою очередь, бьют шары далее.

 Выполнение системы как игра в бильярд

Рис. 6.19. Выполнение системы как игра в бильярд

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

Корневой класс, система и процесс проектирования

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

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

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

В старых концепциях разработки ПО программа рассматривалась как монолитная конструкция, которая состоит из главной программы, разделенной на подпрограммы. При таком подходе трудно использовать старые элементы для новых целей, так как все они создавались как часть конструкции, предназначенной для одной цели. Требовались большие усилия для изменения программы, если менялась цель, как часто бывало на практике.

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

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

Эти наблюдения отражают некоторые из ключевых концепций профессиональной инженерии ПО (в отличие от любительского программирования): расширяемость — простота, с которой можно адаптировать систему при изменении потребностей пользователя со временем; повторное использование — простота использования существующего ПО для нужд новых приложений.

Кирилл Юлаев
Кирилл Юлаев
Федор Антонов
Федор Антонов

Здравствуйте!

Записался на ваш курс, но не понимаю как произвести оплату.

Надо ли писать заявление и, если да, то куда отправлять?

как я получу диплом о профессиональной переподготовке?