Читайте также:
|
|
Nbsp; b) Идеальное состояние Рис.3.6.1-1. Иллюстрация представления памяти в процессе выполнения программы. Занятые участки памяти определяются заштрихованными частями, а все остальные участки являются свободными.При реализации средств управления такой памятью необходимо учитывать следующие важные аспекты. 1. Память для объектов программы выделяется из свободных участков памяти, после чего соответствующие выделенные участки памяти помечаются как занятые (в языке PASCAL выделение памяти может инициироваться выполнением оператора new). При выделении памяти может сложиться такая ситуация, когда требуемый объем непрерывной памяти отсутствует и в то же время общий объем всей свободной памяти имеет достаточно большие размеры. В этом случае выполняется операция сжатия памяти, приводящая состояние памяти к "идеальному" (см. рис. 3.6-1b). 2. Освобождение памяти может инициироваться применением соответствующего оператора программы (в языке PASCAL освобождение памяти может инициироваться выполнением оператора dispose). Однако далеко не всегда следует процесс освобождения возлагать на программиста, поскольку в этом случае предполагается высокий профессионализм и ответственность программиста. Например в языке JAVA освобождение памяти обеспечивается средствами реализации языка. Этот механизм освобождения памяти реализуется в большинстве случаев так называемыми программами сборки мусора. Сборка мусора заключается в маркировке тех участков занятой памяти, на которые есть ссылки из действующих в программе объектов. Затем все немаркированные участки занятой памяти считаются неиспользуемыми в работе программы и освобождаются (то есть переходят в свободный участок памяти). 3.6.2.Генерация кода. Перед генерацией кода в большинстве современных компиляторов происходит формирование так называемого промежуточного кода, с помощью которого осуществляется непосредственно генерация. Основными причинами создания промежуточного кода являются следующие. 1. Необходимость четкого разделения между машинно-зависимой и машинно-независимой частями компиляции. 2. Обеспечение удобства переноса компилятора в другую новую среду. 3. Упрощение реализации средств оптимизации кода. Как правило структура промежуточного кода представляет из себя результат линеаризации синтаксического дерева, содержащего последовательность операторов, каждый из которых является эквивалентным одной машинной команде либо последовательности небольшого числа машинных команд. В качестве языковых средств для описания промежуточного кода выбирают средства, являющиеся адекватными средствам языков, в которые в конечном итоге транслируется исходный текст программы (например в язык машинных кодов или ассемблер). Существуют разные способы представления промежуточных кодов. Здесь ограничимся рассмотрением так называемого трехадресного кода, являющегося одним из наиболее распространенных средств промежуточного кода.Трехадресный код представляется в виде строки a=b op c, где op -оператор, b, c - адреса операндов,a - адрес результата применения оператора к операндам. Например, арифметическое выражение a+b*c-d можно представить в виде последовательности следующих операторов: t1= b*c t1= t1-d t2= a+t1, где t1,t2 -временные переменные, создаваемые компилятором. Допускается также использование унарных операторов, например T1= - R. Каждый оператор трехадресного содержит максимум три адреса. Посредством трехадресного кода можно представлять широкий спектр типичных аспектов языков программирования: присваивание, условные и безусловные переходы и т.п. Например: a=t1 t1=b[i] if t1 goto L1 goto L2 На основе полученного промежуточного кода и специальных таблиц, устанавливающих соответствие между помежуточным и машинным кодами, компилятор генерирует целевой код. 3.6.3.Оптимизация кода. Оптимизация кода позволяет получить эффективный код, в котором обеспечивается оптимальное сочетание двух важных свойств объектного кода: максимально возможная скорость выполнения и минимально возможный объем используемой памяти. Различают два вида оптимизации: - локальная, основывающаяся на относительно простом анализе и преобразованиях кода; - глобальная, основывающаяся на более сложном анализе и преобразованиях кода; Примерами локальной оптимизации являются следующие: - минимизация операций; - снижение стоимости; - исключение ненужных операторов. Минимизация операций предусматривает выполнение в процессе компиляции арифметических операций, которые должны были бы выполняться при выполнении программы. Например последовательность limit:= 100 index:= limit - 1 можно заменить последовательностью limit:= 100 index:= 99. Примером снижения стоимости является замена произведения или деления соответствующими операторами сдвига. Примером исключения ненужных операторов является удаление оператора LOAD, если регистр уже содержит необходимое значение. Глобальная оптимизация, основываясь на анализе потоков управления и информационных связей, обеспечивает более сложные типы оптимизации: - удаление бесполезного кода; - исключение общих подвыражений; - оптимизация циклов. Удаление бесполезного кода предусматривет удаление конструкций программы, которые не будут выполняться при любом выполнении программы. Например в конструкции b:=true;IF b then P else Q оператор Q никогда не будет выполняться. Поэтому данную конструкцию можно заменить эквивалентной конструкцией b:=true; Q. Исключение общих подвыражений заключается в исключении лишних вычислений для повторяющихся подвыражений. Например, последовательность операторов x:= a+b y:= a+b можно заменить последовательностью x:= a+b y:= x. Оптимизация циклов. Наиболее типичными действиями по оптимизации циклов являются вывод из тела цикла "ненужных " операторов и замена цикла фрагментом последовательного кода. Примеры. 1) Конструкцию for i:=1 to 100 do begin x:=y; write(A[i]) end можно заменить эквивалентной конструкцией x:=y; for i:=1 to 100 do write(A[i]) (вывод из тела цикла "ненужных "операторов). 2) Конструкцию while i<N do i:=i+1 можно заменить эквивалентной конструкцией if i<N then i:=N (замена цикла фрагментом последовательного кода) Одним из универсальных подходов к решению проблем оптимизации программ представляется применение так называемого трансформационного программирования, в частности механизма смешанных вычислений, к оптимизации программ. Эти результаты в свое время были получены идеологом нашего отечественного программирования академиком А.П.Ершовым [8]. Суть упомянутого подхода сводится к эквивалентным преобразованиям кода программы на основе применения соответствующих соотношений, например типа if b then P else P º P, (while false do P);Q º Q и т.п. (см. р. 2.4.).
Дата добавления: 2015-02-16; просмотров: 155 | Поможем написать вашу работу | Нарушение авторских прав |