Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
организация памяти.doc
Скачиваний:
13
Добавлен:
09.02.2015
Размер:
186.37 Кб
Скачать

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

Динамическойназывается переменная, память для которой выделяется во время работы программы. У динамической переменной нет имени, - к ней можно обратиться только при помощи специальной переменной, - переменной-указателя.

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

Указателю можно присваивать значение указателя того же типа, константу NIL(пустой указатель) или адрес объекта, определенный с помощью стандартных функций модуляSystem -Addr (ИмяПеременной) (оператора@ИмяПереиенной) иPtr(СегментнаяЧастьАдреса, Смещение).

Сегмент данных— это непрерывная область оперативной памяти с объемом в 65 536 байт (64 Кбайт).

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

Указанное свойство таких переменных весьма полезно при обработке крупных массивов данных. Область памяти, в которой размещаются динамические переменные, называется кучей (heap), максимальный ее объем более чем в 6 раз превышает объем сегмента данных и составляет около 400 Кбайт.

Это не означает, что отдельные переменные (запись или массив) могут иметь такой большой размер. Конечно же, нет: ни одна переменная в Turbo Pascal не может превышать объем 65 520 байт. Однако распределить составляющие записи или массива по различным сегментам памяти оказывается вполне возможным. При этом общий объем «распределенной» переменной может существенно превысить объем отдельного сегмента. Распределение переменной по разным сегментам кучи особенно полезно, когда ее объем заранее предсказать нельзя.

Рекомендуется применять динамические переменные если:

  1. Необходимы переменные, имеющие большой объем и освобождающие память после их использования.

  2. Размер переменной трудно предсказуем.

  3. Размер переменной превышает 64 Кбайт.

Распределение оперативной памяти

Объем оперативной памяти в Turbo Pascal составляет около 640 Кбайт. Эта память делится на сегменты, каждый из которых не превышает 64 Кбайт. В отдельном сегменте размещается код главной программы. Если к программе подключены модули, то по одному такому сегменту выделяется и для каждого модуля. Кроме этого, сегмент памяти обязательно выделяется под стандартный модуль System, автоматически подключаемый к каждой программе. Все перечисленные сегменты носят название сегментов кода, поскольку в них содержатся коды программы или ее модулей.

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

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

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

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

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

{$М «Размер стека», «Минимальный объем динамической памяти», «Максимальный объем динамической памяти»}

Эту директиву применяют в теле программы (после слова BEGIN) перед использованием соответствующих переменных, память в ней измеряется в байтах. Конкретный пример использования такой директивы:

{$М1024,1000 200000}

На рис. 1 приведена компактная схема распределения оперативной памяти, или карта памяти,Turbo Pascal. В этой схеме указанная последовательность сегментов следует снизу вверх. Это достаточно удобно и оправдывает использование синонима «куча» для динамической памяти, которая располагается на схеме в самом верху и, как всякая куча, заполняется снизу вверх.

Рис. 1. Схема распределения оперативной памяти

Согласно этой схеме при отсутствии стандартных и нестандартных модулей максимальный объем динамической памяти, грубо говоря, может составлять

640 - 64*3 - 16 = 432 Кбайт.

Таким образом, при работе с динамическими переменными вы можете рассчитывать на кучу с максимальным объемом около 400 Кбайт.

Как вы знаете, только переменные таких типов, как byte, char, shortInt и boolean, занимают во внутреннем представлении машины один байт (одну ячейку), для размещения переменных всех других простых типов требуется уже нескольких смежных ячеек. Структурированные переменные, например, такие как массивы и записи, могут занимать значительно большие объемы памяти.

Память под динамические переменные выделяется порциями по 8 байт. Поэтому, например, для переменных типа char и shortInt, имеющих размер в один байт, и для real, с объемом в 6 байт, будет выделено по 8 байт. Блоки памяти под переменные больших размеров (массивы, записи и др.) будут кратны 8.

Каждый байт памяти компьютера располагается в отдельной ячейке. Каждая же ячейка памяти имеет свой адрес, по которому к ней можно обратиться. Поэтому адрес часто еще называют указателем или ссылкой. Ясно, что и первые ячейки всех переменных также имеют свои адреса — ведь они ничем не хуже всех других. При этом адреса этих ячеек называют адресами соответствующих переменных. Следует помнить, что адреса всех переменных, как статических, так и динамических, располагаются в сегменте данных и поэтому принадлежат к статической памяти. Каждый такой адрес занимает 4 байта памяти и состоит из двух частей — двух шестнадцатиразрядных слов, которые называются сегментом и смещением. Сегмент — это адрес первой ячейки одного из сегментов памяти, объемом в 64 Кбайт. Смещение указывает число ячеек (или байт), на которое текущий адрес отличается от адреса первой ячейки требуемой переменной.

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

Адреса (или ссылки, указатели) динамических переменных являются статическими переменными и располагаются в сегменте данных, но данные или объекты, на которые они указывают (ссылаются), находятся в куче — динамической памяти. С помощью указателей можно разместить в динамической памяти переменные любых типов. Указатель переменной, в этом случае будет ссылаться на первый байт области памяти, выделенной конкретной переменной заданного типа, а следовательно, и размера.

Стрелочками обозначены типизированные константы-указатели. Все они описаны в модуле System. Первоначально их значение равно Nil.

Nil— это пустая ссылка, то есть адрес ячейки в статической памяти, которая не связана ни с каким объектом в куче, и поэтому объем такой динамической переменной равен нулю. Далее мы подробно рассмотрим, каким образом в эти типизированные константы-указатели записываются адреса соответствующих ячеек кучи. Сейчас же лишь отметим, что при правильной организации работы программы с помощью этих указателей удобно осуществлять управление состоянием кучи. В принципе, можно для аналогичных целей придумать свои идентификаторы. Однако разумнее применять уже существующие, поскольку их объявление не требуется (они уже описаны в модуле System), основываются они на двух английских словах, подсказывающих смысл этих переменных. Заметим здесь, что ptr — сокращение служебного слова pointer (стрелка, указатель) — указатель без типа (нетипизированный указатель или ссылка); org — от origin — начало.

Рис. 2. Верхняя часть карты памяти