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 |
Block1 | Block2 | Block3 |
Рис. 2
После выполнения оператора free(block2) куча будет иметь вид
0х0007 | 0х90EF | … | 0x0008 | 0x0000 | …. | 0x0008 | 0x9116 |
Block1 | Block2 | Block3 |
Рис. 3
Замечание 1. Особенность динамических символьных строк.
Рассмотрим фрагмент кода, создающий динамическую строку.
main()
{
char *str; // ячейка str находится в стеке
str = (char *)malloc(13);
strcpy(str, "Hello,World!");
// строка Hello,World! помещается в кучу
}
Строка "Hello,World!" реально состоит из 13 символов, так как кроме самих символов содержит 0 - признак конца строки. Поэтому, если выделить только 12 элементов
Str = (char *)malloc(12),
то признак конца строки "залезет" на заголовок следующего блока ДП и изменит длину этого блока. Если бы длина строки была меньше 12 байт, то фраза уместилась бы в первом параграфе, и ошибки бы не произошло. Источник хорошо скрытой логической ошибки!
... до тех пор, пока во время счета не выполнится вход в блок, и котором описан массив. При входе в блок вычисляются границы массива и производится обращение к программе распределения памяти для массивов. Здесь же вносится в информационный вектор необходимая информация. Какая информация заносится в информационный вектор? Для предложенной выше n-мерной схемы нам как минимум нужны ...
... .) В системах, в которых страницы инструкций (в противоположность страницам данных) являются реентерабельными, бит изменения никогда не устанавливается. 2. Разработка алгоритма управления оперативной памятью Ниже приведён алгоритм управления оперативной памятью в системе Linux. В основе всего лежат страницы памяти. В ядре они описываются структурой mem_map_t. typedef struct page { /* ...
... производительность 1600 Мбайт/с на двухбайтной шине данных при частоте 400 МГц. Стандарт DRDRAM поддержан множеством производителей микросхем и модулей памяти, он претендует на роль основного высокопроизводительного стандарта для памяти компьютеров любого размера. Подсистема памяти (ОЗУ) DRDRAM состоит из контроллера памяти, канала и собственно микросхем памяти. По сравнению с DDR SDRAM при той ...
... . Несет информацию об адресе текущего элемента однонаправленного динамического списка. q – указатель на структуру news. Несет информацию об адресе последнего созданного элемента однонаправленного динамического списка. news *un,*p,*q; i – переменная типа int. Несет информацию о количестве элементов однонаправленного динамического списка. int i; 4 2) Локальные переменные процедуры ...
0 комментариев