Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

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




При оперативной работе с динамическими структурами данных, не предназначенными для длительного хранения, возникает проблема эффективного использования памяти для хранения небольших структур данных. Системные функции распределения памяти в OS/2 и Windows предоставляют по запросу не менее страницы виртуальной памяти, что естественно расточительно для небольших объектов. Программист, конечно, может после запроса большого блока памяти взять на себя управление выделением из него небольших порций, но было бы удобней и надежней иметь для этого соответствующие системные средства. В основе этих средств лежит динамически распределяемая память, называемая также пулом памяти (pool).

В операционных системах Windows управление динамической памятью сделано весьма разнообразным. Во-первых, каждый процесс при его создании получает пул памяти по умолчанию, который обычно составляет 1 Мбайт. Это значение можно изменить при создании выполняемого EXE-файла с помощью соответствующей опции компоновщика. Если такого общего пула недостаточно при выполнении программы, то набор функций API Windows предоставляет возможности создания дополнительных пулов.

Основной из этих функций является функция с прототипом

HANDLE HeapCreate(DWORD options, DWORD size, DWORD maxsize),

где аргумент maxsize задает максимальный размер создаваемого пула для дальнейших его перераспределений, size – начальный размер пула, а параметр options задает режимы создания, которые в простейших случаях не используются. Функция эта возвращает хэндл созданного пула или NULL при неудаче. Созданный пул по исчезновению потребности в нем должен быть уничтожен функцией HeapDestroy с прототипом

BOOL HeapDestroy(HANDLE hHeap),

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

Для запроса порции памяти из пула служит функция с прототипом

void* HeapAlloc(HANDLE hHeap, DWORD flags, DWORD size),

где hHeap задает хэндл пула, size – размер запрашиваемой порции памяти, а flags задает символическими константами флаги выделения. Среди таких констант наиболее употребительная HEAP_ZERO_MEMORY, задает обнуление выделенного блока памяти. Функция возвращает виртуальный адрес начала запрошенной порции. Хэндл пула может быть получен от ранее выполненной функции HeapCreate или для пула по умолчанию – от функции GetProcessHeap, имеющей прототип

HANDLE GetProcessHeap(VOID).

Функция HeapAlloc аналогична по своему смыслу функции malloc из Unix, но, как видим, более сложна в использовании и привязана к Windows. Обратной ей по действиям (аналогичной функции free из Unix) служит функция HeapFree с прототипом

BOOL HeapFree(HANDLE hHeap, DWORD flags, void* pMem),

где hHeap задает хэндл пула, pMem – адрес начала порции, полученный ранее от функции HeapAlloc, а flags – флаги, которые чаще всего не используются, так что аргумент flags полагается равным нулю.

Дополнительные возможности изменения размеров блоков, полученных из пула, предоставляет функция HeapReAlloc, описываемая прототипом

void* HeapReAlloc(HANDLE hHeap, DWORD flags, void* pMem,DWORD size).

Она позволяет изменить размеры уже имеющегося блока (порции памяти) с адресом pMem из пула с хэндлом hHeap до нового размера size. Флаги, задаваемые в аргументе flags, указываются обычно константами HEAP_REALLOC_IN_PLACE_ONLY и HEAP_ZERO_MEMORY. Первая из них выдвигает требование изменить размер блока, оставляя его на собственном месте (не меняя его виртуального адреса), что выполнимо в большинстве случаев только для уменьшения размера блока. Вторая из этих констант требует заполнить нулями добавляемую часть блока при увеличении его размера.

Дополнительные возможности предоставляет функция с прототипом

DWORD HeapSize(HANDLE hHeap, DWORD *flags, void* pMem),

которая позволяет получить в качестве своего значения размер блока, выделенного по адресу pMem из пула с хэндлом hHeap (одновременно можно получить значение флагов этого блока).

Применение рассмотренных функций для работы с пулом памяти в Windows демонстрирует программа, приведенная в листинге 10.6.1.

 

#include <windows.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

void main()

{char *pblock1, *pblock2, *pblock3;

HANDLE hheap;

hheap=HeapCreate(0,15000, 60000);

if (hheap= =0)

{printf(“Error HeapCreate with RC=%ld\n”, GetLastError());

getchar(); exit(0);}

pblock1=HeapAlloc(hheap, HEAP_ZERO_MEMORY, 1); //min= =12!!

strcpy((char*)pblock1, “piece1”);

printf(“Block1 Adrress=%08X, its size=%ld\n”, pblock1,

HeapSize(hheap,0,pblock1));

printf(“Pause after writing into block1.\n”);getchar();

 

pblock2=HeapAlloc(hheap, HEAP_ZERO_MEMORY, 24);

strcpy((char*)pblock2, “second piece”);

printf(“Block2 Adrress=%08X, its size=%ld\n”, pblock2,

HeapSize(hheap,0,pblock2));

printf(“Pause after writing into block2.\n”);getchar();

pblock3=HeapAlloc(hheap, HEAP_ZERO_MEMORY, 27);

 

pblock2=HeapReAlloc(hheap, 0, pblock2,47);

printf(“After realesing block2.\n”);getchar();

printf(“Block2 Adrress=%08X, its size=%ld\n”, pblock2,

HeapSize(hheap,0,pblock2));

printf(“Contens of block1 = %s, its size=%ld\n”, pblock1,

HeapSize(hheap,0,pblock1));

HeapFree(hheap, 0, pblock1);

printf(“Pause after realesing block1.\n”);getchar();

printf(“Contens of block2 = %s, its size=%ld\n”, pblock2,

HeapSize(hheap,0,pblock2));

HeapDestroy(hheap);

}

Листинг 10.6.1. Управление пулом памяти в Windows

 

Вначале программа создает новый пул памяти с возможным максимальным размером в 60 000 байтов и текущим размером в 16 000 байтов. После этого из нового пула функцией HeapAlloc запрашивается 1 байт памяти (а выделяется 12 – меньше не выделяется). Затем той же функцией запрашиваются порции по 24 и 27 байтов. Во все полученные таким образом блоки памяти записывается текстовая информация, затем второй блок изменяется в размере до 47 байтов, первый блок освобождается. В завершение созданный ранее пул уничтожается.

Для сравнения в листинге 10.6.2 приведена аналогичная программа работы с динамической памятью в Unix.

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

void main()

{char *pm, *pblock1, *pblock2, *pblock3, *pblock2a;

pblock1=malloc(7);

strspy((char*)pblock1, “piece1”); 0

printf(“Bloc{1 adrress=%08X\n”, pblock1);

0 printf(“Pause after writing i~to block1.\n”);getchar();

 

0 pblock2=malloc(24);

strcpy((char*)pblock2, “second piece”); 0

printf(“Block2 adrress=%08X\n”, pblock2);

printf(“Pause after writing into block2.\n”);getchar();

 

pblock3=malloc(27);

strcpy((char*)pblock3, “third piece”);

printf(“Block3 adrress=%08X\n”, pblock3);

printf(“Pause after writing into block3.\n”);getchar();

 

pblock2a=realloc(pblock2,47);

printf(“After realloc pblock2a=%08X\n”, pblock2a);

if (pblock2a!=NULL) pblock2=pblock2a;

printf(“Block2 adrress=%08X\n”, pblock2);

printf(“Contens of block1 = %s\n”, pblock1);

free(pblock1);

printf(“Contens of block2 = %s\n”, pblock2);

free(pblock2);

printf(“Contens of block3 = %s\n”, pblock3);

free(pblock3);

}

Листинг 10.6.2. Управление пулом памяти в Unix

 

Непосредственное сравнение последних программ показывает, что API Unix дает самые компактные и простые для использования программистом средства управления памятью.

Упражнение

Разработать многопоточную программу, отображающую на экране взаимодействие трех нитей "читателей" из общей области данных и двух "писателей", записывающих в этот буфер данные. Буфер предназначен для хранения 10 символов. Первая нить-писатель выводит в буфер данные в латинском алфавите, вторая нить-писатель выводит в буфер данные в русском алфавите. Такой вывод эти две нити осуществляют в два приема, первый из которых записывает половину своего текста без завершающего этот промежуточный текст нуля. Между такими половинами вывода нити производят задержку на случайную величину миллисекунд, но не более 2 с. После вывода своего текста в буфер каждая нить-писатель переходит в ожидание порядка 2-3 с до следующей попытки записи в буфер. Нити-читатели через случайный интервал порядка 300 мс. читают данные из буфера, если это позволяют средства синхронизации доступа между нитями, и выводят прочитанный текст на экран, каждая в свой столбец. Каждый вывод нити-читателя осуществляется в новую строку своего столбца, поэтому суммарные действия вывода в таких нитях предусмотреть только для 20 – 24 строки. Синхронизацию осуществить с помощью семафоров (возможны два вариант задания – для Windows и для Linux).

 




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


Дата добавления: 2014-01-05; Просмотров: 664; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.026 сек.