Т. Пратт, М. Зелковиц - Языки программирования - разработка и реализация (4-е издание_ 2002) (1160801), страница 126
Текст из файла (страница 126)
Огромная разница между последним стандартом этого языка, РОКТКАХ 90, и предылущими версиями заключается как раз в том, что в ЕОКТКАХ 90 допускается (в ограниченном объеме) динамическое распределение памяти. Рааса! был специально разработан таким образом, чтобы управление памятью основывалось на использовании стеков, Е15Р— чтобы допускался сбор мусора и т. д. Несмотря на то что при разработке каждого языка обычно предполагается применение определенного метода управления памятью, детали механизмов управления, их представление в аппаратуре и программном обеспечении являются задачами разработчика транслятора языка.
Например, хотя Е15Р позволяет использовать в качестве основы для управления памятью список свободного пространства и сбор мусора, однако существует несколько различных методов сбора мусора, из которых разработчик транслятора должен выбрать наиболее подходящий с учетом доступной аппаратуры и программного обеспечения компьютера.
К управлению памятью имеет отношение и процаммист, который должен при разработке программ наиболее эффективно использовать память, но у него чаще всего 460 Глава 10. Управление памятью почти нет прямых способов управления памятью. Программа управляет памятью только косвенно, посредством использования или неиспользования различных возможностей языка.
Положение программиста еше более усложняется характерной для разработчиков языков и разработчиков трансляторов тенденцией относить управление памятью к машинно-зависимым вопросам, которые не должны явно рассматриваться в руководствах по языкам. Таким образом, программисту во многих случаях совсем не просто выяснить, какой метод управления памятью применяется на самом деле. 10.1.
Размещаемые в памяти элементы С точки зрения программиста, управление памятью — это обычно выделение областей памяти для хранения данных и кода оттранслированных программ. Однако управление памятью во время выполнения включает, помимо этих, много других областей. Пекоторые из них, как, например, точки возврата из подпрограмм, нами уже обсуждались в предыдущих главах.
Здесь мы рассмотрим основные элементы программ и данных, которые необходимо размещать и сохранять в памяти во время выполнения программы. + Сегменты кода для оттранслированных программ пользователя. В любой системе основной блок памяти отводится для хранения сегментов кода, представляющих оттранслированную форму программ пользователя, независимо от используемого метода интерпретации — аппаратного или программного. В первом случае программы будут представлены блоками выполняемых машинных команд, во втором случае блоки будут содержать информацию в некоторой промежуточной форме. + Системные программы времени вьтолнвния.
Другой значительный блок памяти во время вьшолнсцня должен быть отведен для размешения системных программ, которые поддерживают выполнение программы пользователя. Диапазон этих программ обширен — от простых библиотечных программ, вычисляющих тригонометрические функции или выводящих строки символов на печать, до программных интерпретаторов или трансляторов, присутствуюших во время выполнения. Сюда же относятся и программы, управлян)щис распределением памяти эо время выполнения. + Оггределяемыв пользователем структуры данных и константы.
Для всех структур данных, объявленных в пользовательских программах или созданных ими, включая константы, требуется выделить место в памяти. + Точки возврата для подпрограмм. Подпрограммгя могут вызываться в различных точках программы. Следовательно, внутренне сгенерированная информация об управлении последовательностью действий, как то: точки возврата из подпрограмм, точки возобновления выполнения сопрограмм или сообщения о событиях для план пру е мы х подпрограмм, — также должна быть размещена в памяти.
+ Среды ссылок. Размещение сред ссылок (ассоциаций идентификаторов) во время выполнения программы может потребовать значительных ресурсов памяти, как, например, для А-списка в языке 116 Р (приложение, раздел П 6). !Од. Размещаемые в памяти элементы 461 Кр рации наибо + Временная память для вычисления выражений. При вычислении выражений необходимо использовать определяемую системой временную память для хранения промежуточных результатов вычисления.
Например, при вычислении выражения (х + у! х (э + ч) может возникнуть необходимость сохранения результата первого сложения во временной памяти, пока будет вычисляться второе сложение. Если в выражении присутствуют рекурсивные вызовы функций, для хранения промежуточных результатов на каждом уровне рекурсии может потребоваться потенциально неограниченный объем временной памяти. Временная память при передаче параметров, При вызове подпрограммы должен быть вычислен список фактических параметров и получаемые результаты должны сохраняться во временной памяти, пока пе будет полностью вычислен весь список параметров. Если вычисление какого-либо параметра приводит к рекурсивным вызовам функции, то, как и в случае вычисления выражений, может потребоваться потенциально неограниченный объем памяти.
Буферы ввода-вывода. Обычно операции ввода и вывода работают с ис пользованием буферов, которые служат в качестве временных областей памяти для хранения данных в промежутке между моментом их фактической передачи с внешнего устройства или на него и моментом выполнения инициированных программой операций ввода или вывода. Различные системпгве данные. В реализации почти каждого языка требуется память для хранения различных системных данных: таблиц, информации о состоянии устройств ввода-вывода и другой разнообразной информации о состоянии (например, счетчики ссылок или биты сбора мусора). оме перечисленных элементов программ и структур данных, некоторые опетакже требуют выделения или освобождения памяти.
Ниже перечислены лес существенные из таких операций. Операции вызова и возврата из подпрограмм. При вызове подпрограммы требуется выделить намять для размещения записи активации подпрограммы, среды локальных ссылок и лруп1х данных. При выполнении операции выхода из подпрограммы обычно требуется освободить дополнительную память, выделенную при вызове подпрограммы. Операции создания и уничтожения структур данных Если в языке предусмотрены операции, позволяющие в произвольной точке программы (а не только на входе в подпрограмму) создавать новые структуры данных (например, операция пеи в языке )ача), то эти операции обычно требуют выделения памяти отдельно от той, которая выделяется при входе в подпрограмму. Язык может также предоставлять явные операции уничтожения ранее созданных структур данных, например функции й эрозе в Рааса! и Ггее в С, которые могут потребоваться для освобождения выделенной под какие-то структуры данных памяти.
В )ага такая явная операция отсутствует; для этого предназначен процесс сбора мусора. Операции вставки и удаления компонентов. Если язык предоставляет операции вставки и удаления компонентов структур данных, то для их реализа- 462 Глава 10. Управление памятью ции может потребоваться выделение и освобождение памяти (например, функция роза в языке Рег! добавляет злемент к массиву). Хотя перечисленные операции требуют явного управления распределением памяти, существует множество других операций, которые подразумевают некоторое скрытое управление памятью, по большей части связанное с вьщелением и освобождением памяти при осуществлении различных вспомогательных действий (например, при вычислении выражений и передаче параметров).
10.2. Память, управляемая программистом и системой До какой степени следует позволять программисту непосредственно управлять распределением памяти? С одной стороны, популярность языка С объясняется отчасти тем, что он предоставляет программисту широкие возможности явного управления памятью посредством операций аа11ос и Ггее, которые соответственно выделяют память для структур данных, определяемых программистом, и освобождают ее. С другой стороны, многие языки высокого уровня не дают программисту никаких средств прямого управления памятью; на распределение ресурсов памяти можно влиять только косвенным образом путем использования тех или иных возможностей языка, Возможность прямого управления распределением памяти программистом связана с двумя трудностями; во-первых, зто управление может оказаться тяжелым и часто нежелательным бременем для программиста, и, во-вторых, оно может вступать в противоречие с осуьцествляемым системой необходимым управлением распределением памяти.