Nickolay.info. Обучение. Лекции по Си. Глава 11

11. Модели памяти

 

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

·       размер кода программы превышает 64 Кб;

·       размер статических данных программы превышает 64 Кб.

Имеется два варианта выбора модели памяти для программы:

·       назначить нужную модель в опциях компилятора;

·       использовать в объявлении объектов программы модификаторы near, far и huge.

Можно комбинировать эти способы.

Архитектура процессоров, основанных на базе 8086/8088, предусматривает разбиение оперативной памяти на физические сегменты, способные содержать информацию объемом до 64 Кб. Минимальное количество сегментов, выделяемое программе, равно двум: сегмент кода и сегмент статических данных. К статическим данным при этом относятся все объекты, объявленные с классом памяти extern или static. Формальные параметры функций и локальные переменные не являются статическими. Они хранятся не в сегменте данных, а в стеке (однако при этом стек может быть совмещен со стандартным сегментом данных физически).

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

Адрес оперативной памяти состоит из двух частей:

·       базовый адрес сегмента - 16‑битовое число;

·       смещение относительно начала сегмента - также 16-битовое число.

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

Если код или данные находятся в другом сегменте по отношению к адресующему, для доступа к ячейке памяти должны и адрес сегмента, и смещение. В этом случае указатели объявляются с модификатором far (дальний). Доступ к объектам по дальним указателям позволяет программе адресовать всю оперативную память, а не только в пределах сегмента размером 64 Кб.

Наконец, указатели с модификатором  huge (максимальный) также включают адрес сегмента, и смещение, но имеют иную адресную арифметику. Поскольку объекты, адресуемые far указателями, не выходят за границу адресуемого сегмента, действия по вычислению адресов  выполняются только над смещением дальних указателей. Это ускоряет доступ, но ограничивает размер одного программного объекта объемом 64 Кб. Для указателей huge арифметические действия выполняются над всеми 32 битами адреса.

Тип адреса huge определен только для данных, таких как  массивы и указатели на них. Таким образом, никакой из исходных файлов, составляющих программу, не должен  генерировать более 64 Кб кода.

Кратко опишем шесть имеющихся в Си моделей памяти.

Минимальная модель (tiny). Код вместе с данными не превышает по объему 64 Кб. Применялась для исполняемых файлов, преобразуемых к формату *.com.

Малая модель (small). Программа занимает 2 стандартных сегмента: сегмент кода и сегмент данных, в котором размещается также стек. Как код, так и данные программы не могут превышать 64 Кб. Модель подходит для большинства несложных программ и назначается компилятором по умолчанию. Для доступа к объектам кода или данных по умолчанию используются указатели типа near.

Средняя модель (medium). Для данных и стека выделяется один сегмент, для кода - произвольное число сегментов. Каждому исходному модулю программы выделяется собственный сегмент кода. Модель применяется для программ с большим количеством кода (более 64 Кб) и небольшими объемами данных (менее 64 Кб). Для доступа к функциям по умолчанию используются указатели far, а для доступа к данным - указатели near. Модель предлагает компромисс между скоростью выполнения и компактностью кода, поскольку многие программы чаще обращаются к данным, чем к функциям.

Компактная модель (compact). В этой модели выделяется один сегмент для кода, и произвольное число сегментов для данных. Модель применяется для небольших программ, работающих со значительными объемами данных. Доступ к функциям производится по указателям near, а к данным - по указателям far.

Большая модель (large) использует по несколько сегментов и для кода, и для данных. Модель подходит для больших программ со значительным объемом данных. В этой модели доступ к элементам кода и данных производится по указателям типа far. Как и во всех предшествующих моделях умолчания можно обойти, явно используя модификаторы near, far и huge там, где они требуются при объявлении данных и функций.

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

Максимальная модель требует учитывать некоторые особенности языка при обращении к операции sizeof и вычитании указателей. По умолчанию значение sizeof имеет тип unsigned int, однако число байтов в huge массиве должно быть представлено типом unsigned long. Для получения правильного значения следует делать приведение типа:

(unsigned long)sizeof(huge_array)

Аналогично, результат вычитания указателей определен в Си как значение типа int. При вычитании указателей типа huge результат может иметь тип long. В этом случае также требуется сделать приведение типа:

(long)(huge_item1-huge_item2)

 

 

Рейтинг@Mail.ru
вверх гостевая; E-mail