911 Динамическое распределение памяти

Здесь указан адрес переменной в формате [сегмент]:[смещение]. Полный адрес переменной равен 8FAC0+FFF4=9FAB4

- Для переменной ptri, описанной как

int i = 4, *ptri;

ptri = &i;

окно просмотра имеет вид

8FAC:FFF2

п

Ds:FFF4

[0]

 

4(0x0004)

Int *

Здесь указаны: адрес самой переменной ptri, равный 8FAC:FFF2; значение этой переменной Ds:FFF4; а также содержимое ячейки по адресу Ds:FFF4, т.е. значение i. Для того, чтобы узнать содержимое ячеек, окружающих переменную i, нужно воспользоваться комбинацией клавиш Alt-I, ввести начальный индекс (Starting index) и число ячеек (Count). Если, например, введены числа -5 и 15, то можно в приведенном выше окне можно просмотреть элементы массива ptri[-5], ptri[-4],…,ptri[10].

Объекты, размещенные в куче, не имеют имени. Поэтому просматривать динамические объекты можно только предыдущим способом, т.е. по адресу.

Абсолютные адреса и размеры областей памяти в модели large

Область кода занимает часть ОЗУ, содержащую параграфы с номерами от CS до DS-1. Таким образом, размер области кода равен (DS-CS)*0x10.

Область данных занимает часть ОЗУ, содержащую параграфы с номерами от DS SS-1. Таким образом, размер области данных равен (SS-DS)*0x10.

Стек начинается с параграфа SS, но растет справа налево, от старших адресов к младшим. Новые данные помещаются в стек в вершине стека. Смещение вершины стека относительно SS равно SP. Таким образом, полный адрес вершины равен SS:SP. В начале программы стек пуст, поэтому он занимает ячейки с адресами от SS*0x10 до SS*0x10, а размер стека равен SP.

На кучу остается память с адреса SS*0x10+SP по 0xA0000=640K.

Реальный размер кучи зависит от способа запуска программы. Сама оболочка Borland C++2.0 занимает в ОЗУ порядка 200K, и для программы, выполнямой из оболочки, остается немного места - примерно 300K. Если же программа запускается из командной строки DOS или из Norton Commander, то куча будет значительно больше.

При выполнении программы из оболочки и в отладчике под кучу отводится еще меньше места, поэтому ее размер в этом случае разрешается устанавливать вручную с помощью опции Options-Debugger-Program heap size.

2. Основные функции ДРП

Выделение памяти

void *malloc(size_t size);

Выделяет блок ДП размером size байт. Здесь size_t совпадает с типом unsigned int. Таким образом, блок не превосходит размер в 64K. В случае отсутствия непрерывного блока заказанной длины, возвращается NULL.

Пример 1. Выделение массива для 1000 чисел типа float.

main() {

float *ptrf;

if((ptrf =(float *) malloc(1000 * sizeof(float)) == NULL)

printf("\nОшибка при выделении памяти!");

}

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

void free(void *block);

Освобождает блок ДП, начинающийся с адреса block. Этот адрес должен находится в заголовке ранее выделенного блока (см. п.3). В противном случае, будет освобожден случайный блок и возникнет логическая ошибка. Динамические переменные не освобождаются автоматически при выходе из области действия и, таким образом, засоряют кучу.

Перевыделение памяти

void *realloc(void *block, size_t size);

Изменяет размер блока, на который указывает block. Новый размер блока будет равен size. Старая информация сохраняется. При нехватке свободных байт блок будет перемещен в новое место с одновременным копированием информации. Функция возвращает адрес нового блока, не изменяя переменную block.

Пример 2. Выделение памяти под двумерный массив

main() {

float **A;

int n=5, n=10;

A = (float **)malloc(m * sizeof(float *));

if(A == NULL)

{

printf("\nОшибка при выделении памяти под массив указателей!");

exit(1);

}

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

{

A[i] = (float *)malloc(n * sizeof(float));

if(A[i] == NULL)

{

printf("\nОшибка памяти под%d-ую строку!", i);

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

free(A[j]);

free(A);

exit(2);

}

//…….

for(i=0; i< m; i++)

free(A[i]);

free(A);

}

3. Менеджер ДРП

Управлением ДП занимается специальный фрагмент кода, вызываемый в функциях ДРП. Он называется менеджером ДП. Мы исследуем работу менеджера в модели памяти large. В других моделях менеджер устроен по-другому.

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

Выделяемый блок памяти имеет вид

2

2

14

16

16

В заголовке находятся:

¾ длина блока в параграфах (2 байта),

¾ сегментный адрес предыдущего блока (2 байта),

¾ далее идут данные. Адрес начала данных и возвращается функциями ДРП.

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

Таким образом, зная адрес последнего занятого блока, можно определить длину, адрес и статус остальных блоков. Рассмотрим программу

main(){

char *block1=(char *)malloc(100);

char *block2=(char *)malloc(110);

char *block3=(char *)malloc(120);

free(block2);

}

Выполняя ее в отладчике, увидим, что до освобождения второго блока куча будет иметь вид (конкретные адреса будут другими!)

0х0007

0х90EF

0x0008

0x910F

….

0x0008

0x9116

 

Страница:  1  2  3  4 


Другие рефераты на тему «Программирование, компьютеры и кибернетика»:

Поиск рефератов

Последние рефераты раздела

Copyright © 2010-2024 - www.refsru.com - рефераты, курсовые и дипломные работы