УПРАВЛЕНИЕ ПАМЯТЬЮ НА УРОВНЕ ПРОЦЕССОВ



Память является важнейшим ресурсом, требующим тщательного управления со стороны мультипрограммной операционной системы [6, 11, 12, 13, 15, 17]. Распределению подлежит вся оперативная память, не занятая операционной системой. Обычно ОС располагается в самых младших адресах, однако может занимать и самые старшие адреса. Функциями ОС по управлению памятью являются: отслеживание свободной и занятой памяти; выделение памяти процессам и освобождение памяти при завершении процессов; вытеснение процессов из оперативной памяти на диск, когда размеры основной памяти не достаточны для размещения в ней всех процессов, и возвращение их в оперативную память, когда в ней освобождается место, а также настройка адресов программы на конкретную область физической памяти.

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

Типы адресов

Для идентификации переменных и команд используются символьные имена (метки), виртуальные адреса и физические адреса (рис. 4.1).

 


Рис. 4.1. Типы адресов

 

Символьные имена присваивает пользователь при написании программы на алгоритмическом языке или ассемблере.

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

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

Второй способ заключается в том, что программа загружается в память в неизмененном виде в виртуальных адресах, при этом операционная система фиксирует смещение действительного расположения программного кода относительно виртуального адресного пространства. Во время выполнения программы при каждом обращении к оперативной памяти выполняется преобразование виртуального адреса в физический. Второй способ является более гибким, он допускает перемещение программы во время ее выполнения, в то время как перемещающий загрузчик жестко привязывает программу к первоначально выделенному ей участку памяти. Вместе с тем использование перемещающего загрузчика уменьшает накладные расходы, так как преобразование каждого виртуального адреса происходит только один раз во время загрузки, а во втором случае – каждый раз при обращении по данному адресу [12].

Функции супервизора памяти

Управление основной памятью осуществляет супервизор памяти, являющийся компонентом управляющей программы.

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

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

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

Супервизор памяти выполняет следующие функции:

1) учет свободных участков основной памяти (основа управления основной памятью);

2) выделение участков памяти по запросам;

3) освобождение участков памяти, выделенной ранее по запросу;

4) борьба с фрагментацией памяти;

5) многоуровневое распределение основной памяти;

6) повышение уровня мультипрограммирования. 

Учет свободных участков

Любое управление памятью основано на учете свободных участков памяти, который организуется связыванием всех свободных участков в цепочку. Каждый из них представляется элементом FQE, располагаемым в начале свободного участка, и имеет следующую структуру:

{размер свободного участка; адрес следующего элемента}

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

Пример очереди свободных участков приведен на рис.4.2,а. Свободные участки имеют размеры l1, l2, l3. Начальный адрес очереди расположен в одном из управляющих блоков. Например, если распре-деление памяти производится на уровне пункта задания, то адрес начала очереди располагается в одном из полей блока управления задачей (ТСВ) пункта задания. Заштрихованные на рисунке области представ-ляют собой занятые участки основной памяти, выделенные ранее по запросам [12].

Выделение участков памяти по запросам

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

- при запросе, равном 11. При этом очередь свободных участков будет иметь вид, приведенный на рис. 4.2,б;

- при запросе, равном l4 < l1. При этом очередь свободных участков будет иметь вид, приведенный на рис. 4.2,в.

Освобождение участков памяти

Удовлетворение запроса на освобождение участка памяти означает, что участок возвращается под контроль супервизора путем включения в очередь нового элемента FQE, представляющего данный участок как свободный, или путем изменения указателя размера свободного участка, смежного с освобождаемым [12].

Борьба с фрагментацией памяти

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

 

Рис. 4.2. Примеры очередей свободных участков:

l5=l1l4, где l4 - размеры запроса

 

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

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

Способы борьбы с фрагментацией памяти:

- расширение размера основной памяти. Например, виртуальная память позволяет расширить размер основной памяти и сделать его значительно превышающим размер реальной оперативной памяти;

- упорядочение запросов на участки памяти по времени освобож-дения. Желательно, чтобы участки памяти, освобождаемые примерно в одно и то же время, располагались в смежных областях. При этом после освобождения участков образуется единая область свободной памяти достаточно большого размера. Такое упорядочение происходит путем классификации запросов и направления их в разные области памяти, что достигается использованием аппарата подпулов, предоставляемого управлением памятью;

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

- включение алгоритмов сборки мусора. Во многих задачах, обрабатывающих данные сложной структуры, которые включают кроме самих данных также адресные ссылки, бывает сложно определить момент, когда элемент данных становится ненужным и может освобо-дить занимаемую память. Примером служит обработка многосвязных списков, где допускается непредсказуемое число перестраиваемых ссылок на элементы данных. При этом для определения всех элементов данных, ставших ненужными в текущий момент, включается алгоритм сборки мусора. Этот алгоритм может сочетаться с алгоритмом перестройки структуры данных с целью объединения отдельных свобод-ных фрагментов памяти в общую область [12].

Контрольный пример

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

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

Программа реализована на языке Си и одинаково корректно работает в DOS и в DOS-сессии Windows.

 

/* ЛИСТИНГ ПРОГРАММЫ */

 

#include <stdio.h>

#include <conio.h>

#include <bios.h>

#include <dos.h>

#define ESC 27

#define INS  82

#define DEL 83

#define dX 14           //ширина окна процесса

#define dY 4            //высота окна процесса

#define ID_COUNT 16     //количество процессов

#define TIME 0.01    //время выполнения процесса

#define DELAY -6000 //задержка в тыс.операций для отключения

/     массив координат окон для процессов   */

int xy[2][ID_COUNT]={{01,01,01,01,17,17,17,17,33,33,33,33,49,49,49,49},{01,07,13,19,01,07,13,19,01,07,13,19,01,07,13,19}};

/* массив статуса процессов: 0 – свободен, 1 – на выполнении */

int ID[ID_COUNT]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

typedef unsigned char BYTE ;

/*                прототипы функций                     */

void ShowMenu();     //главное меню

void ShowCursor();   //показать курсор

void HideCursor();   //спрятать курсор

/*               описание класса процесса            */

class TProcess

 {

int id;          //номер процесса

BYTE x,y;         //координаты окна процесса

public:

long CountOperations; //кол-во операций процесса

TProcess *next; //указатель на следующий процесс

TProcess *prev; //указатель на предыд. процесс

int GetID();  //получить номер процесса

long GetTime(); //получить кол-во невыполненных операций

void GetParams(); //задать параметры процесса

void ShowWND(); //показать окно процесса

void HideWND(); //спрятать окно процесса

void ActiveWND(); //активизировать окно процесса

int Time();      //выполнение процесса

 };

/*метод получения количества невыполненных операций*/

long TProcess::GetTime()

{

return CountOperations;

}

int TProcess::Time() //метод выполнения процесса в течении кванта времени

{

double th1,th2;

struct time t;

ActiveWND();

gettime(&t);

th1=t.ti_hour*60*60+t.ti_min*60+t.ti_sec

+(double)(t.ti_hund)/100;

do

{

th2=0;

gettime(&t);

gotoxy(2,2);

if (CountOperations<0)

       cprintf("Complete...     ");

else

{

  cprintf("%2d:%02d:%02d.%02d",t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);

  cprintf(" %8ld",CountOperations);

}

th2=t.ti_hour*60*60+t.ti_min*60+t.ti_sec

+(double)(t.ti_hund)/100;

--CountOperations;

}

while(th2<=th1+TIME);

return 0;

}

void TProcess::ActiveWND() //метод активизации окна выполнения процесса

{

textcolor(14);

textbackground(1);

window(x+1,y+1,x+dX-1,y+dY-1);

}

void TProcess::HideWND() //метод удаления окна выполнения процесса с экрана

{

textcolor(15);

textbackground(0);

window(x,y,x+dX,y+dY);

clrscr();

}

/*метод вывода окна выполнения процесса на экран*/

void TProcess::ShowWND()

{

textcolor(15);

textbackground(1);

window(x,y,x+dX,y+dY);

clrscr();

window(x,y,x+dX,y+dY+1);

cprintf("┌[Process #%2d]┐",id);

cprintf("│        │");

cprintf("│        │");

cprintf("│        │");

cprintf("└─────────────┘");

ActiveWND();

}

/*метод получения номера текущего процесса*/

int TProcess::GetID()

{ return id;}

/*метод создания нового процесса*/

void TProcess::GetParams()

{

ShowCursor();

for(int i=0;i<ID_COUNT;i++)

if (!ID[i]) break;

ID[i]=1;

id=i;

textcolor(15);

textbackground(0);

window(1,24,80,24);

clrscr();

cprintf("Создание нового процесса # %d.",id);

cprintf(" Количество операций (в тысячах) = ");

if (!cscanf("%ld",&CountOperations)) CountOperations=DELAY-1000;

CountOperations*=1000;

x=xy[0][id];

y=xy[1][id];

prev=NULL;

next=NULL;

HideCursor();

}

/*прототип ф-ции задания процесса для удаления */

TProcess * GetDelProcess(TProcess *);

/*прототип функции очистки командеой строки*/

void ClearCommandLine();

void MemoryShowWND(class TProcess * BPtr);

int main(void)

{

int key, count;

long d;

class TProcess * ptr1=NULL;

class TProcess * ptr2=NULL;

class TProcess * BPtr=NULL;          //указатель на начало списка процессов

class TProcess * EPtr=NULL;       //указатель на конец списка процессов

HideCursor();

textcolor(15);

clrscr();

ShowMenu();

MemoryShowWND(BPtr);

do

{

/*обраб. процессов,пока не нажата любая клавиша*/

ptr1=BPtr;

do

{

       if (!BPtr) continue;

       ptr1=ptr1->next;

       ptr1->Time();

       d=ptr1->GetTime();

       if (d<DELAY)

       {

       ptr1->prev->next=ptr1->next;

       ptr1->next->prev=ptr1->prev;

       if (ptr1==BPtr) BPtr=ptr1->next;

       if (ptr1==EPtr) EPtr=ptr1->prev;

       if (ptr1==BPtr&&ptr1==EPtr) EPtr=BPtr=NULL;

       ptr1->HideWND();

       ID[ptr1->GetID()]=0;

       delete ptr1;

       MemoryShowWND(BPtr);

       }

}                   // ожидание нажатия клавиши

while (!_bios_keybrd(_KEYBRD_READY)) ;

/*     обработка нажатия клавиши        */

key = getch();

if (!key) key = getch();

switch(key)

{

case INS:           //создание нового процесса

        for(int i=0,count=0;i<ID_COUNT;i++)

       if (!ID[i]) {count=1;break;}

        if (!count)

        {

       ClearCommandLine();

       cprintf("\n\nНевозможно создать новый процесс.Уже создано 20 процессов.");

       break;

        }

        ptr2 = EPtr;

        ptr1 = NULL;

        ptr1 = new TProcess;

        if (!ptr1)

        {

       ClearCommandLine();

       cprintf("\n\nОшибка выделения памяти для нового процесса.");

       break;

        }

        if (!BPtr) BPtr=ptr1;

        EPtr=ptr1;

        ptr1->GetParams();

        ptr1->prev=ptr2;

        ptr2->next=ptr1;

        BPtr->prev=EPtr;

        EPtr->next=BPtr;

        ptr1->ShowWND();

        ClearCommandLine();

        MemoryShowWND(BPtr);

        break;

case DEL:          //удаление процесса

        ptr1=GetDelProcess(BPtr);

        if (ptr1)

        {

       ptr1->prev->next=ptr1->next;

       ptr1->next->prev=ptr1->prev;

       if (ptr1==BPtr) BPtr=ptr1->next;

       if (ptr1==EPtr) EPtr=ptr1->prev;

       if (ptr1==BPtr&&ptr1==EPtr) EPtr=BPtr=NULL;

       ptr1->HideWND();

       ID[ptr1->GetID()]=0;

       delete ptr1;

       ClearCommandLine();

       MemoryShowWND(BPtr);

        }

        break;

}

}

while(key!=ESC);                       //выход по нажатию Esc

//удаление всех процессов

ptr1=BPtr;

do

{

if (!ptr1) break;

delete ptr1;

ptr1=ptr1->next;

}

while(ptr1!=BPtr);

textcolor(15);

textbackground(0);

window(1,1,80,25);

clrscr();

return 0;

}

void ClearCommandLine()

{

textcolor(15);

textbackground(0);

window(1,24,80,24);

clrscr();

}

/*функция получения номера процесса для удаления*/

TProcess * GetDelProcess(TProcess * BPtr)

{ int id;

TProcess *ptr, *ptrf=NULL;

ClearCommandLine();

ShowCursor();

cprintf("Введите номер процесса для удаления : ");

cscanf("%d",&id);

HideCursor();

ptr=BPtr;

do

{ if (!ptr) break;

if (ptr->GetID()==id)

{

ptrf=ptr;

break;

}

ptr=ptr->next;

}

while(ptr!=BPtr);

if (!ptrf)

{

clrscr();

cprintf("Ощибка. Процесс #%d не найден.",id);

//if (!getch()) getch();

}

return ptrf;

}

/*вывод рабочего меню на экран*/

void ShowMenu()

{

 textbackground(7);

 window(1,25,80,25);

 clrscr();

 textcolor(4); cprintf(" INS");

 textcolor(0); cprintf(" - создать новый процесс ");

 textcolor(4); cprintf(" DEL");

 textcolor(0); cprintf(" - удалить процесс ");

 textcolor(4); cprintf(" ESC");

 textcolor(0); cprintf(" - выход из программы ");

}

/*функция гашения курсора*/

void ShowCursor()

{

asm{

mov ah,1

mov bh,0

mov cx,0606h

int 10h

}

}

/*функция восстановления курсора*/

void HideCursor()

{

asm{

mov ah,1

mov bh,0

mov cx,2000h

int 10h

}

}

void MemoryShowWND(class TProcess * BPtr)

{

class TProcess * ptr1=NULL;

int coun=2;

textcolor(15);

textbackground(3);

window(65,1,80,23);

clrscr();

window(65,1,80,24);

cprintf("┌[Адрес памяти]┐");

ptr1=BPtr;

do

{

if (!ptr1) break;

cprintf("│#%2d %p│",ptr1->GetID(),ptr1);

++coun;

ptr1=ptr1->next;

}

while(ptr1!=BPtr);

for(int i=coun;i<23;i++)

cprintf("│         │");

cprintf("└──────────────┘");

}

Для создания процесса необходимо нажать клавишу INS, затем внизу экрана в командной строке (строка запроса) ввести количество операций в тысячах для процесса с указанным номером (рис. 4.3). После чего на экране возникнет новое окно – окно выполнения процесса, в котором выводится значение текущего времени и текущее количество операций для выполнения (рис. 4.4). Далее процесс автоматически зано-сится в список процессов для выполнения, имеющий кольцевидную (замкнутую) структуру. В правой части экрана в окне «Адрес памяти» выводится номер и адрес вновь созданного процесса.

 

 

Рис. 4.3. Создание нового процесса

 

 

 

Рис. 4.4. Перечень адресов активных процессов с отображением их адресов памяти

Если процесс выполнил требуемое количество операций, то на экра-не возникает надпись о его завершении «Complete …» и через малый промежуток времени окно процесса исчезает с экрана (рис. 4.5). При этом сам процесс удаляется из списка заданий, и в окне адресов памяти исчезает номер и адрес данного процесса.

 

 

Рис. 4.5. Перечень активных и завершенных процессов

 

Для удаления процесса в произвольный момент времени необходи-мо нажать клавишу DEL и в строке запроса ввести номер процесса для удаления. Если процесс с указанным номером будет найден, то он исчез-нет с экрана и удалится из списка обрабатываемых процессов и окна адресов памяти. Для выхода из программы необходимо нажать ESC.

Лабораторная работа № 4

Цель работы: разработать программу-менеджер, осуществляющую управление оперативной памятью при создании, размещении и удалении процессов.

Результат:  отчет о лабораторной работе и программа, управляющая размещением процессов в памяти.

 

Список вариантов

 


Дата добавления: 2018-04-15; просмотров: 338; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!