Дисциплина: Современные компьютерные архитектуры Тема 2: СРЕДА ВРЕМЕНИ ВЫПОЛНЕНИЯ ПРОГРАММ Лекция 2.1: Управление памятью Москва 2018 1 УЧЕБНЫЕ ВОПРОСЫ 1. Организация памяти 2. Выделение памяти в стеке 3. Доступ к нелокальным данным в стеке ЦЕЛЬ ЗАНЯТИЯ: Сформировать теоретические знания в области основных принципов выделения физической памяти вычислительным процессам и организации адресного пространства вычислительного процесса. ЛИТЕРАТУРА: 1. Ахо А.В., Лам М.С., Ульман Д.Д. Компиляторы: принципы, технологии и инструментарий. М.: изд-во Вильямс, 2015. – С. 525-554 2. Столмен Р., Пеш Р., Шебс С. Отладка с помощью GDB. 2000. – С. 51-53 2 1.1 Организация памяти вычислительного процесса Вычислительный процесс - некоторое преобразование f(x), где x – n-мерная величина, характеризующая множество исходных данных программы, f(x) – m-мерный результат работы программы. Инструкции (операции) и данные (операнды) – два базовых типа объектов, находящихся в адресном пространстве вычислительного процесса. Каждый объект обладает уникальным адресом месторасположения в адресном пространстве вычислительного процесса. Всего существует три типа адресов: логический адрес - используется в инструкциях машинного языка для обозначения адреса операнда или оператора; линейный адрес - 32-разрядное или 64-разрядное целое без знака, которое можно использовать для адресации до 232 (или 264 соответственно) ячеек памяти; физический адрес - используется для адресации ячеек в микросхемах памяти. 3 1.2 Организация памяти вычислительного процесса Минимально адресуемой единицей физической памяти, не требующей использования специальных инструкций процессора, является байт. Требование к размещению данных в памяти по адресам кратным степеням двойки называется выравниванием памяти. //предполагается, что sizeof(int) == 4 struct x { char c1; //смещение 0, размер 1 байт //байты 1-3: 3 заполняющих байта int i1; //байты 4-7: 4 байта на 4 байтовой границе char c2; //байт 8: 1 байт //байты 9-11: 3 заполняющих байта }; В данном примере n==1+3+4+1=9 и m==sizeof(x)==12. 4 1.3 Организация памяти вычислительного процесса Память выделяемая процессу операционной системой в общем случае используется для хранения: • Целевого кода программы; • Сохранения состояний вычислительного процесса в ходе его выполнения; • Сохранения статических и динамических ресурсов вычислительного процесса. Код Статические данные Куча Фиксируется во время компиляции программы Глобальные константы и данные сгенерированные компилятором Хранение структур данных, требуемый размер памяти для которых неизвестен Свободная память Стек Хранение записей активации, генерируемых при вызовах процедур 5 1.4 Организация памяти вычислительного процесса Статическим ресурсом вычислительного процесса называются какие-либо данные, используемые программой, для которых решение о выделении памяти принимается во время компиляции, когда известен только исходный текст программы, но не то, что именно программа делала в процессе работы. Динамическим ресурсом вычислительного процесса называются какие-либо данные, используемые программой, для которых решение о выделении памяти принимается исключительно во время выполнения программы. Стек используется для хранения структур данных, называющихся записями активации. Записи активации генерируются при вызове процедур в ходе выполнения вычислительного процесса. 6 2.1 Выделение памяти в стеке Активация – специальная структура данных, размещающаяся в стеке процесса каждый раз при вызове процедуры и хранящая исчерпывающую информацию о состоянии вычислительного процесса в момент передачи потока управления вызывающей процедуры вызываемой, параметрах передаваемых в вызываемую процедуру и возвращаемых ею в вызывающую процедуру. Последовательность вызовов процедур в ходе исполнения программы формирует дерево активаций. 1. Корень дерева активации – главная процедура, например main. 2. Дочерние вершины узла p – активации процедур, вызванных из p. 3. Активации указываются слева направо и сверху вниз в порядке их вызова. 7 2.2 Выделение памяти в стеке Пример программы, реализующей считывание девяти целых чисел в массив a и сортирующей его с помощью рекурсивного алгоритма быстрой сортировки: 8 2.3 Выделение памяти в стеке В процессе активации процедуры возможна одна из трех ситуаций: • активация q завершается нормально, управление возвращается в точку p, следующую непосредственно за точкой, в которой был сделан вызов q; • активация q или некоторой процедуры, вызванной q прямо или косвенно, завершается аварийно, в этом случае p завершается одновременно с q; • активация q завершается из-за сгенерированного исключения, которое q обработать не в состоянии, процедура p может обработать исключение, в этом случае активация q завершается, в то время как активация p продолжается, хотя и не обязательно с точки, в которой была вызвана q. Вызов процедур и возвраты из них управляются стеком времени выполнения, именуемым стеком управления. Активная активация имеет запись активации (кадр в стеке управления). 9 2.4 Выделение памяти в стеке Примерное содержимое записи активации: Фактические параметры Возвращаемые значения Связь управления Связь доступа Состояние машины Локальные данные Временные переменные Фактические параметры, используемые вызываемой процедурой. Память для возвращаемого значения (может размещаться в регистре) Указывает на запись активации вызывающей процедуры Используется для обращения вызванной процедуры к данным в другой записи активации Информация о состоянии машины (адрес возврата, содержимое регистров) Локальные данные процедуры Значения, появляющиеся в процессе вычисления выражений. 10 2.5 Выделение памяти в стеке Снимки стека времени выполнения при прохождении управления по дереву активаций из рассмотренного ранее примера: 11 2.6 Выделение памяти в стеке За реализацию вызова процедуры отвечают как вызывающая, так и вызываемая процедуры, при этом используются следующие принципы: • Значения, передаваемые между вызывающей и вызываемой процедурами, помещаются в начале записи активации вызываемой процедуры; • Элементы фиксированного размера размещаются посередине записи активации; • Элементы, размер которых может быть не известен заранее, размещаются в конце записи активации; • Указатель стека указывает на конец полей фиксированного размера в записи активации. Доступ из записи активации вызывающей процедуры к записи активации вызываемой процедуры осуществляется через содержимое регистра top_sp, который указывает на конец поля состояния машины в текущей записи активации. 12 2.7 Выделение памяти в стеке Организация вызова вызывающей процедурой вызываемой и обратный возврат продемонстрированы на рисунке: 13 2.8 Выделение памяти в стеке Стратегия выделения памяти в стеке для массивов переменной длины показана на рисунке: 14 3.1 Доступ к нелокальным данным в стеке В современных языках программирования переменные (операнды) делятся на два класса - локальные и глобальные. Глобальная переменная имеет область видимости, которая состоит из всех функций, следующих после ее объявления, за исключением мест, где имеется локальное определение идентификаторов, имя которых совпадает с идентификатором глобальной переменной. Переменные, объявленные внутри функции, имеют область видимости, состоящую только из тела этой функции. Глубина вложенности процедур, которые не вложены ни в какую иную процедуру равна единице. Если процедура p определена в процедуре с глубиной вложенности i, то глубина вложенности такой процедуры p составляет i+1. 15 3.2 Доступ к нелокальным данным в стеке Непосредственная реализация обычного статического правила области видимости для вложенных функций получается путем добавления в каждой записи активации указателя, называющегося связью доступа. Если в исходном тексте программы процедура p непосредственно вложена в процедуру q, то связь доступа в каждой активации p указывает на последнюю активацию q. При вызове процедурой q процедуры p возможны три ситуации: 1. процедура p имеет большую глубину вложенности, чем q. В таком случае p должна быть определена непосредственно в q, иначе вызов процедурой q оказывается не в пределах области видимости имени процедуры p. Таким образом, глубина вложенности процедуры p ровно на единицу больше глубины вложенности q и связь доступа должна вести от p к q; 2. вызов рекурсивен, то есть q=p. В этом случае связь доступа для новой записи активации та же, что и запись активации ниже нее в стеке; 3. глубина вложенности np процедуры p меньше глубины вложенности np процедуры q. Для того чтобы вызов в q находился в области видимости имени p, процедура q должна быть вложена в некоторую процедуру r, а p должна быть процедурой, определенной непосредственно в r. 16 3.3 Доступ к нелокальным данным в стеке 1) fun sort(inputFile, outputFile) = let 2) val a = array(11,0); 3) fun readArray(inputFile) = … ; 4) ... a … ; 5) fun exchange(i,j) = 6) ...a… ; 7) fun quicksort(m,n) = let 8) val v = … ; 9) fun partition(y,z) = 10) ...a… v…exchange … in 11) ...a…v…partition…quicksort end in 12) ...a…readArray… quicksort… end; 17 3.4 Доступ к нелокальным данным в стеке 18 3.5 Доступ к нелокальным данным в стеке Пример программы на языке ML, использующей передачу функции в качестве параметра. 1)fun a(x) = let 2) 3) 4) fun b(f) = …f…; fun c(y) = let 5) fun d(z) = … in 6) …b(d)… end in 7) …c(1)… end; Дисплей – вспомогательный массив m, который содержит по одному указателю m[i] на наивысшую запись активации в стеке для процедуры с глубиной вложенности i. 19 3.6 Доступ к нелокальным данным в стеке 20 УЧЕБНЫЕ ВОПРОСЫ 1. Организация памяти 2. Выделение памяти в стеке 3. Доступ к нелокальным данным в стеке 1. 2. 3. 4. 5. 6. 7. 8. ВОПРОСЫ ДЛЯ САМОСТОЯТЕЛЬНОЙ ПОДГОТОВКИ Изучить материалы литературы [1 стр. 525-554], [2 – стр. 327-333]. Повторить способы выделения и освобождения динамической памяти в языке программирования C. Повторить определение указателя на объект в терминологии языка программирования C. Структура адресного пространства вычислительного процесса. Запись активации (определение, состав). Дерево активации вычислительного процесса (принципы построения) Организация доступа к нелокальным данным в стеке. Использование дисплеев. 21