Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
6262.pdf
Скачиваний:
34
Добавлен:
13.02.2021
Размер:
6.54 Mб
Скачать

 

95

 

while (buf[i] != 0) {

 

 

if (buf[i] == 0x20) {

// Прочитали слово

 

buf[i] = 0;

 

 

pw[++j]= &buf[i + 1];

 

}

 

 

i++;

 

 

}

 

 

printf("%10s - Общий размер программы (в страницах)\n",

pw[0]);

printf("%10s - Размер резидентной части памяти\n", pw[1]);

printf("%10s - Число разделяемых страниц\n",

pw[2]);

printf("%10s - Число страниц 'code'\n",

pw[3]);

printf("%10s - Число страниц data/stack\n",

pw[4]);

printf("%10s - Число страниц library\n",

pw[5]);

printf("%10s - Число страниц

dirty («грязных»)\n",

pw[6]);

puts("\nЗапускаю дочерний процесс:"); system("lab8.3");

puts("\nДочерний процесс завершил работу ...");

puts("Завершение проекта lab8.4 ..."); return EXIT_SUCCESS;

}

Задание 2.4

Скопировать файл ~/lab8/lab8.3/Debug/lab8.3 в директорию ~/bin.

Всреде разработки Eclipse, создать проект с именем lab8.4, руководствуясь текстом листинга 2.4.

Отладить и провести исследование работы полученной программы. Сравнить системные характеристики программ lab8.3 и lab8.4. Отразить краткое описание работы данного примера в личном отчете.

2.5.4Динамическое выделение и освобождение памяти процесса

Впредыдущих подразделах были рассмотрены случаи выделения памяти, которые осуществляются ядром ОС.

Вданном подразделе, мы изучим системные вызовы ОС, обеспечивающие выделение памяти для нужд программиста. Для этих целей существует ряд функций, позволяющих выделять и освобождать память ОЗУ динамически, во время выполнения программы. Эти функции имеют следующее определение:

#include <stdlib.h>

void *malloc(size_t size); void free(void *ptr);

void *calloc(size_t nmemb, size_t size); void *realloc(void *ptr, size_t size);

Семантика этих функций - следующая:

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

96

указателя NULL;

free(...) — освобождает память ОЗУ, которая ранее была выделена одной из функций: malloc(...), calloc(...) или realoc(...); если аргумент функции равен NULL, то никаких действий не производится;

calloc(...) - выделяет память ОЗУ под массив данных, размерность которого задана первым аргументом, а размер каждого элемента массива в байтах, задан вторым аргументом; при этом, значение каждого байта выделенной памяти обнуляется; возвращает указатель на выделенный массив данных; если значение любого из аргументов функции равно нулю, то память ОЗУ процессу не выделяется и возвращается значение NULL;

realloc(...) - изменяет размер уже выделенного блока памяти, используя первый аргумент как указатель, а второй — как нужный размер; если размер области уменьшается, то значения байт оставшейся области не изменяется; если размер области увеличивается, то добавляемая область не инициализируетсся; если значение аргумента указателя равно NULL, то результат функции, соответствует действию функции malloc(...); если требование на новый размер памяти равно нулю, а указатель не равен NULL, то действие эквивалентно функции free(...).

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

Листинг 2.5 - Пример программы динамического выделения памяти программе

#include <stdio.h> #include <stdlib.h> #include <malloc.h>

void * ptr1 = NULL; void * ptr2 = NULL;

int main(void) {

puts("Проект lab8.5 ...");

printf("Размеры областей ptr1,ptr2 до выделения ОЗУ:\n"); printf(" ptr1 =%10lu\n", malloc_usable_size(ptr1)); printf(" ptr2 =%10lu\n", malloc_usable_size(ptr2));

printf("Выделяем 100 байт по 1 Кбайт для первой области\n"); if(!(ptr1 = (char*)malloc(100*1024))){

printf("Не могу выделить память..."); exit(EXIT_FAILURE);

}

printf("Размеры ptr1,ptr2 после выделения ОЗУ malloc():\n"); printf(" ptr1 =%10lu\n", malloc_usable_size(ptr1)); printf(" ptr2 =%10lu\n", malloc_usable_size(ptr2));

printf("Выделяем ОЗУ из, 10 элементов массива по 1 Кбайт, для второй области\n");

ptr2 = calloc(10, 1024);

printf("Размеры ptr1,ptr2 после выделения ОЗУ calloc():\n"); printf(" ptr1 =%10lu\n", malloc_usable_size(ptr1)); printf(" ptr2 =%10lu\n", malloc_usable_size(ptr2));

97

printf("Освобождаем 1-ю область ОЗУ:\n"); free(ptr1);

printf("Размеры ptr1,ptr2 после освобождения ОЗУ:\n"); printf(" ptr1 =%10lu\n", malloc_usable_size(ptr1)); printf(" ptr2 =%10lu\n", malloc_usable_size(ptr2));

puts("Завершение проекта lab8.5 ..."); return EXIT_SUCCESS;

} // Конец листинга 2.5

Задание 2.5

С помощью утилиты man, провести изучение функций: malloc(...), calloc(...), realloc(...) и free(...).

В среде разработки Eclipse, создать проект с именем lab8.5 и набрать текст программы, руководствуясь текстом листинга 2.5.

Отладить и провести исследование работы полученной программы. Отразить краткое описание работы данного примера в личном отчете.

Кроме перечисленных, имеются также системные функции brk(...) и sbrk(...), с помощью которых можно непосредственно изменять конец сегмента неинициализированных данных.

Синтаксис этих системных вызовов:

#include <unistd.h>

int brk (void *addr); void *sbrk(intptr_t increment);

Семантика системных вызовов:

brk(...) - устанавливает конец сегмента данных в значение, указанное в аргументе addr, когда это значение является приемлимым; указание адреса памяти должно быть в пределах максимально возможного размера сегмента данных (см. setrlimit(2));

sbrk(...) - увеличивает пространство данных программы на increment байт; sbrk(...) не является системным вызовом, он просто является оберткой (wrapper), которую использует библиотека C для вызова brk(...); вызов sbrk(...) с инкрементом 0 может быть использован, чтобы найти текущее местоположение прерывания программы.

Вслучае успеха brk(...) возвращает ноль, а sbrk(...) возвращает указатель на начало новой области. В случае ошибки, возвращается -1 и значение errno устанавливается в значение ENOMEM.

На листинге 2.6 приведен пример программы, которая с помощью функции sbrk(...) три раза изменяет границу сегмента неинициализированных данных.

98

Листинг 2.6 - Пример использования функции sbrk(...)

#include <stdio.h> #include <stdlib.h> #include <unistd.h>

char * ptr = NULL;

int main(void) {

puts("Проект lab8.6 ..."); ptr = sbrk(0);

if (ptr == (char *)-1)

{

perror("Нет доступного пространства для sbrk(...)\n"); exit(EXIT_FAILURE);

}

printf("Первый адрес после добавляемой области: %23lp\n", (char *)ptr);

ptr = sbrk(4096);

if (ptr == (char *)-1)

{

perror("Нет доступного пространства для sbrk(...)\n"); exit(EXIT_FAILURE);

}

printf("Первый адрес после первого добавления 4096 байт: %14lp\n", (char *)ptr);

ptr = sbrk(4096);

if (ptr == (char *)-1)

{

perror("Нет доступного пространства для sbrk(...)\n"); exit(EXIT_FAILURE);

}

printf("Первый адрес после второго добавления 4096 байт: %14lp\n", (char *)ptr);

ptr = sbrk(0);

if (ptr == (char *)-1)

{

perror("Нет доступного пространства для sbrk(...)\n"); exit(EXIT_FAILURE);

}

printf("Первый адрес после добавленной области: %23lp\n", (char *)ptr);

ptr = sbrk(8192); ptr = sbrk(8192);

if (ptr == (char *)-1)

{

perror("Нет доступного пространства для sbrk(...)\n"); exit(EXIT_FAILURE);

}

printf("Первый адрес после двойного добавления по 8192 байт: %10lp\n", (char *)ptr);

puts("Завершение проекта lab8.6 ..."); return EXIT_SUCCESS;

} // Конец листинга 2.6

99

Задание 2.6

В среде разработки Eclipse, создать проект с именем lab8.6. Набрать текст программы, руководствуясь текстом листинга 2.6. Отладить и провести исследование работы полученной программы.

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

Замечание

При выполнении задания 2.6 необходимо внимательно отслеживать: когда функция sbrk(...) показывает на начало выделенной области, а когда — за конец выделенной области.

Этим заданием, лабораторная работа №8 — заканчивается.

Не забудьте оформить отчет о проделанной работе.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]