Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТЯП, ТВП / ТЯПМТ / Пособие.doc
Скачиваний:
160
Добавлен:
11.05.2015
Размер:
2.37 Mб
Скачать

8. Распределение памяти

8.1. Стек времени прогона

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

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

int x,

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

struct (int number, real size, bool n) y,

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

int z[10],

то объем памяти, необходимый для хранения всех элементов z, в 10 раз больше памяти для записи одного целого значения. Однако, если быwбыл описан в виде

int w[n],

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

Память нужна также для промежуточных результатов и констант. Например, при вычислении выражения a + c d сначала вычисляетсяc d, причем значение запоминается в машине, а затем выполняется сложение. Память, используемая для хранения результатов, называетсярабочей. Рабочая память может быть статической и динамической.

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

Integer a, b, X, y

выделяется память, как это показано на рис. 8.1.

A

B

X

Y

Рис. 8.1. Распределение памяти для Фортрана

Такая схема не учитывает тот факт, что рабочая память используется неоднократно и весьма неэффективна для языка с блочной структурой.

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

Пусть имеется программа вида:

begin real x, y

.

.

.

begin int c, d

.

.

.

end

begin char p, q

.

.

.

end

.

.

.

end

На рис. 8.2 показаны «моментальные снимки» стека времени прогона на различных этапах ее выполнения.

d

q

c

p

y

y

y

x

x

x

(1)

(2)

(3)

Рис. 8.2. Стек времени прогона

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

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

q

p

x

ДИСПЛЕЙ

y

СТЕК

Рис. 8.3. Система «дисплей-стек»

Это упрощает настройку указателя при выходе из блока.

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

Рассмотрим пример программы:

begin int n; read(n);

int numbers[n];

real p;

begin real x, y;

Место для numbers должно выделяться в первой рамке стека, а длях иу– в рамке над ней. Но во время компиляции неизвестно, где должна начинаться вторая рамка, так как неизвестен размер чисел. Одно из решений в этой ситуации – иметь два стека: один для статической памяти, распределяемой в процессе компиляции, а другой для динамической памяти, распределяемой в процессе прогона.

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

Рамка

2

у

х

Числа

Динамическая часть

Рамка

1

p

Статическая часть

n

Дисплей

Стек

Рис. 8.4. Стек прогона для массива

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

Рамка

2

у

х

Элементы

чисел

Динамическая часть

Рамка

1

p

Статиче

Статическая часть чисел

ская часть

n

Дисплей

Стек

Рис. 8.5. Модифицированный стек прогона для массива

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