www.uchites.ru Лекции по курсам "Теоретические основы информатики" и "Языки программирования" В. Е. Зайцева (МАИ) Глава 1. Распределение памяти 1.1 Статические и динамические объекты программ [47], с.8-11. [67], с.533-557. [03]. гл. 7. [21]. с. 70-72. Некоторые свойства объекта и связи с другими объектами остаются неизменными при любом исполнении его области действия (участка программы, где этот объект считается существующим). Такие свойства и связи называются статическими. Их можно определить по тексту программы, без ее исполнения. Например, в Паскале тип объекта одно из статических свойств. Сама o6ласть действия объекта - по определению статическое его свойство. Связь двух объектов по свойству принадлежать одной области действия - статическая связь. Свойство объекта при любом исполнении области действия принимать значения только из фиксированной совокупности значений - статическое свойство. Исчерпывающий перечень применимых к объекту операций статическое свойство. Другие свойства и связи изменяются в процессе исполнения области действия. Их называют динамическими. Например, конкретное значение переменной - динамическое свойство. Связь формального параметра с конкретным фактическим в результате вызова процедуры динамическая связь. Размер конкретного массива с переменными границами - динамическое свойство. Часто статические и динамические характеристики называют соответственно характеристиками периода компиляции (трансляции) и периода выполнения (runtime), подчеркивая то обстоятельство, что в период компиляции исходные данные программы недоступны и. следовательно, динамические характеристики известны быть не могут. Известны лишь характеристики, извлекаемые непосредственно из текста программы и тем самым относящиеся к любому ее исполнению (т.е. статические характеристики). Это деление характеристик на статические и динамические иногда оказывается слишком черно-белым. Например, размер массива - формального параметра, подпрограммы на Фортране - с границами регулируемой размерности - также формальными параметрами может меняться от вызова к вызову в зависимости от значения фактических параметров-границ. Так что это и не чисто статическая характеристика, и не вполне динамическая, как значение переменной, которое можно изменить любым оператором присваивания. Возможна и более тонкая классификация характеристик по фактору изменчивости. Например, связывают изменчивость не с областью действия, с периодом постоянства других его избранных характеристик (выделяемой объекту памяти, связи с другими объектами и т.п.). Уровень изменчивости характеристик объектов языка - одно из важнейших свойств языка. Одна крайняя позиция представлена концепцией неограниченного динамизма, когда по существу любая характеристика обрабатываемого объекта может быть изменена при выполнении программы. Такая концепция не исключает прогнозирования и контроля, но и не связывает их жестко со структурой текста программы. Неограниченный динамизм присущ не только всем машинным языкам, но и многим языкам высокого уровня. Эта концепция в разной степени воплощена в таких интерпретативных динамических языках, как Бейсик, Апл, Лисп, CLU, Smalltalk, CLOS и т.п. Другая крайняя позиция выражена в стремлении затруднить программисту всякое изменение характеристик объектов. Вводя объект, надо объявить характеристики, которым должно соответствовать всякое его использование. Конечно, неограниченной статики в программировании добиться невозможно (почему?). Так что всегда разрешается менять, например, значения объявленных переменных. Зато остальные характеристики в таких статических языках изменить трудно. Обычно стремятся к статике ради надежности программ (за счет их дополнительной избыточности при 1 www.uchites.ru обязательном объявлении характеристик возникает возможность дополнительного контроля) и скорости объектных программ (больше связей можно выполнить при трансляции и не тратить на это времени в период исполнения). Вместе с тем сама по себе идея объявления характеристик (прогнозирования поведения) и контроля за их инвариантностью требует создания, истолкования и реализации соответствующего языкового аппарата. Поэтому статические языки, как правило, сложнее динамических, их описания объемнее, реализации тяжеловеснее. Если память выделяется (распределяется) в процессе трансляции и ее объем не меняется от начала, до конца выполнения программы, то такой объект является статическим. Если же память выделяется во время выполнения программы и ее объем может меняться, то такой объект является динамическим. Поскольку транслятор распределяет память на основе информации, содержащейся в описаниях объектов программы, то все объекты, описанные в основной Паскаль-программе являются статическими, в отличие от локальных переменных процедур. Язык Паскаль допускает использование и динамических объектов. При этом динамический объект не может иметь собственного имени, так как все идентификаторы, кроме идентификаторов стандартных подпрограмм, должны быть описаны в соответствующих разделах Паскальпрограммы. Поэтому в языке Паскаль принято не именовать, а обозначать динамический объект, присоединяя символ | к имени переменной-ссылки на этот динамический объект. Переменнаяссылка должна быть описана в разделе var Паскаль-программы как переменная ссылочного типа и, следовательно, сама она является статическим объектом. Ссылочный тип - это такой же простой тип, как целый, вещественный и логический. Элементами множества, значений этого типа являются значения адресов единиц оперативной памяти конкретной машины, для которой предназначается Паскаль-программа (например, адресов машинных слов ЭВМ). Для названия ссылочного типа в языке Паскаль не зарезервировано никакого специального идентификатора: <ссылочный тип> := | <имя типа> Таким образом, ссылочный тип - что множество значений, указывающих на объекты некоторого одного типа. Ссылочное значение nil принадлежит любому из ссылочных типов. Оно указывает на отсутствие связи с объектом (аналогично нулю, который указывает на отсутствие количества). Ссылочный тип может быть именованным и неименованным. В первом случае в разделе type Паскаль-программы ему надо дать имя. Например, type Т= . . . ; { тип динамического объекта } pointer=|T;{ имя ссылочного типа - pointer } Теперь элементами множества значений этого типа являются адреса областей памяти, достаточных для размещения объектов типа Т. Имя pointer можно употребить при описании переменной-ссылки: var p:pointer; При использовании неименованного ссылочного типа. переменная-ссылка должна быть описана следующим образом: var р:|Т; В обоих случаях, обрабатывая описание переменной р, транслятор выделит для хранения значений этой переменной достаточное место в оперативной памяти (например, одно машинное слово, если его достаточно для хранения адресных значений). При этом следует учитывать, что эта область памяти находится в том состоянии, в котором она оставалась после предыдущего ее использования, т.е. там располагается некоторая последовательность 0 и 1, не определенная данной программой (значение НЕОПР [4, 5]. В отличие от системной константы nil, имеющей и имя. и постоянное значение (известное, правда, только разработчикам транслятора), используемое для указания на отсутствие ссылки на какой-либо объект, за неопределенностью (НЕОПР) не 2 www.uchites.ru закреплено ни имени, ни значения (от случая к случаю в отведенных областях памяти оказываются, как правило, различные последовательности 0 и 1). Поэтому, если транслятор не контролирует использование неопределенных значений, такая последовательность 0 и 1 может быть интерпретирована как ссылка на объект и это обусловит возможность доступа к случайной области памяти и может привести к непредсказуемому эффекту. Для переменных ссылочного типа (ссылок) определена единственная операция: сравнение на равенство (если не считать присваивания). Если, например, результатом сравнения p=nil является значение true, то ссылочная переменная р не указывает ни на какой объект. Динамические объекты определенного типа порождаются (в момент резервирования памяти для хранения его значений) при выполнении стандартной процедуры new, фактическим параметром которой является ссылка на этот тип данных. Так, динамический объект типа Т порождается при выполнении оператора new (р); при этом переменная р получает значение адреса начала области памяти, выделенной для хранения значения типа Т, а сама эта область памяти содержит пока значение НЕОПР. При работе процедуры new память для динамических объектов выделяется из так называемой "кучи" (части оперативной памяти машины, зарезервированной для этой цели). Процедура new фактически находит не использованную до данного момента область памяти подходящего размера и соответственно присваивает переменной-ссылке значение начального адреса этой области. Размер ''кучи" в системе обычно фиксирован. Поэтому, если процедура new вызывается многократно, то может наступить такой момент, когда вся память, предназначенная системой для динамических переменных, будет исчерпана, и программа не сможет продолжить работу. В языке Паскаль определена также специальная процедура dispose, "уничтожающая" динамический объект, ссылка на который передана ей в качестве фактического параметра. Поэтому обработка динамических объектов обычно происходит по следующей схеме: new(p);{ порождение динамического объекта р| } { обработка динамического объекта р| } dispose (p); { уничтожение динамического объекта } Однако точный результат работы (основной эффект) процедуры dispose в стандарте языка Паскаль не определен, поэтому реализация этой процедуры целиком зависит от решений, принятых разработчиком транслятора. В простейших версиях процедура dispose не выполняет вообще никаких действии. Более сложные версии дают возможность повторного использования памяти, занимаемой динамическим объектом, возвращая ее в "кучу" в присваивая переменнойссылке р значение nil. Динамическими объектами в оперативной памяти можно также считать различные процессы, задачи, потоки. 1.2 Распределение памяти под локальные объекты функций и процедур [6]. Блочная структура программ (см. 1 семестр) предполагает локальные переменные, которые удобно размещать в стеке, естественным образом обеспечивая их омонимию. Своеобразным случаем блочной структуры можно считать рекурсивный вызов процедур, при котором неявным образом динамически формируется семейство вложенных блоков со своими копиями локальных переменных. Найдите больше информации на сайте Учитесь.ру (www.uchites.ru)! 3