#15 Память. Теория.

Вступление

Здраствуйте!
С прошедшим вас Новым годом и наступающими остальными праздниками!
Я был в кратковременном отпуске, поэтому выпуски не выходили некоторое время. Но, как говорится the show must go on...
Сегодня мы займёмся чисто теоретическими вопросами об устройстве памяти и тому подобными вещами. Несмотря на отсутствие каких либо программ это нужно прочитать, что бы иметь представление о том, что пойдёт дальше. Если что-то будет непонятно - пишите.

И ещё одна новость - рассылка перебирается на сайт - http://web-pascal.narod.ru. Кроме рассылки там можно скачать себе компилятор, почитать документацию и статьи. Надеюсь этот сайт вам понравится.

Теория

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

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

Пока наши программы являются программами реального режима работы процессора (он называется Real Mode). Этот режим использовался на первых процессорах семейства 8086/88 (ну и на некоторых моделях далее, сейчас он оставлен для совместимости). Те Pentium'ы и Celeron'ы, которые стоят у вас являются дальними родственниками 8086. На этих процессорах использовалась сегментная модель памяти. Что это значит? Это значит, что вся память разбивается на куски (сегменты), например вот так:

ПАМЯТЬ
сегмент 0 сегмент 1 сегмент 2 и т.д.

Так вот каждый сегмент имеет размер в 64 Kb. Из одной большой памяти мы сделали много маленьких :) Однако нам нужно знать точное положение переменной в памяти (т.е. указав номер сегмента, мы укажем только с точностью до 64 Кб). Для этого укажем её смещение относительно начала сегмента, т.е. сегмент выглядит так:

сегмент 1
смещение 0 смещение 1 смещение 2 и т.д.

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

Реальный (физический) адресс расчитывается таким образом: Address = Segment * 16 + Offset

Понятно, что для разных пар Segment и Offset мы можем иметь один и тот же физический адрес. Например эти пары указывают на одино и то же место в памяти:

10FA:01C2
10F0:0262
10E0:0362
Замечу, что цифры, используемые в этой записи - шеснадцатеричные, если вы чувствуете себя не очень среди них, то вернитесь к выпуску #2 (
http://web-pascal.narod.ru/ras/stunde/s2.htm), где объяснено о том, что это такое.

Таким образом формально мы можем иметь доступ к адресам с 00000 - FFFFFh ( буква h в конце числа означает, что это число шеснадцатерично).. Замечу, что при Segment = FFFFh и Offset = FFFFh мы получим Address = 10FFEFh. Однако ввиду ограничения на шину адреса в 20 бит (т.е. размер Address в 20 бит, 20 двоичных цифр) эта комбиинация физически указывает на 0FFEFh - т.е. получается как бы кольцо с небольшим нахлёстом.

Кстати наши программы тоже разбиты на сегменты. Различают сегмент кода, сегмент данных и сегмент стека. В сегменте данных хранятся все наши глобальные переменные. В сегменте кода находится код, который исполняет процессор (т.е. все наши процедуры, функции и главная часть программы от begin до end.). И в сегменте стека хранятся локальные переменные и кое-какая служебная информация. Со стеком мы уже сталкивались в предыдущих выпусках.

Естесственно, что сегменты кода, данных и стека имеют размер в 64 Kb (сегмент стека может быть и меньше, его размер задаётся опцией Stack size, о которой говорилось в предыдущих выпусках). Например напишем такую программу:

program test;

var
 a : array [0 .. 65535] of byte;

begin
end.
вроде бы ничего особенного. Просто большой массив. Однако попробуем запустить .... бац Error 22: Structure too large.(размер структуры слишком большой). Нетрудно понять, что наш массив не влезает в 1 сегмент, который отведён для данных. Точно так же обстоят дела и с кодом и со стеком. Ошибку переполнения стека мы уже разбирали.

Получается, что в сумме память, которую использует наша программа равна 64 + 64 + 64 = 192 Кб. ??? Зачем же тогда на компьютеры ставят так много памяти?

Так как наши программы работают в Real Mode, нам доступен только 1 Мбайт памяти (на самом деле ещё меньше) - максимальное число из 20 двоичных цифр. Остальные доступны в только защищённом режиме работы процессора.

Те 192 Кб, которые мы насчитали называют статическими (т.к. они неизменны). Переменные, созданные в разделе переменных называются статическими переменными. В противоположность им есть динамические переменные - те память под которые выделяется и освобождается программистом.

Ниже приведено распределение памяти:

  • 00000h - 9FFFFh - Base Memory, 640 Кбайт - стандартная память, доступная программам реального режима. Распределена следующим образом:
    • 00000h - 003FFh - Interupt Vectors - векторы прерываний, что это такое я раскажу позже.
    • 00400h - 004FFh - BIOS Data Area - область переменных Bios.
    • 00500h - 00xxxxh - DOS Area - область DOS
    • 00xxxxh - 9FFFFh - User RAM - память, доступная для использования.
  • A0000h - FFFFFh - Upper Memory Area (UMA), 384 Кбайта - верхняя память, зарезервированая для системных нужд. Например, в ней размещается память адаптеров.
  • 10000h и выше - Extended Memory - дополнительная память, непосредственно доступная только в защищенном режиме процесора.
Что бы не осталось недоговорок: защищённый режим (Protected Mode). Впервые появился на 80286 процессоре. Попытки выполнения недопустимых команд, выхода за рамки отведённого пространства памяти и областей ввода/вывода контролируются системой защиты. В защищённом режиме работает, например Windows (и соответственно программы для него), а в реальном режиме DOS (большинство ДОС программ так же работают в этом режиме).

Для интересующихся могу дать одну интересную ссылку - http://www.subscribe.ru/catalog/comp.soft.prog.intelpm Рассылка "Процессор INTEL в защищенном режиме" (автор Broken Sword). Рассылка, скажу сразу, не для тех, кто только начал (хотя ссылку сохраните - пригодится позже :).

добавление

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

var
c : file of integer;
т.е. указать тип сразу после имени переменной, не описывая его предварительно. Вот это я и хотел добавить.

Послесловие

До встречи, и ещё раз с праздниками!


[Назад] [Содержание] [Дальше]
Hosted by uCoz