Научная статья на тему 'Эффективные методы распределения памяти для операционной системы Windows'

Эффективные методы распределения памяти для операционной системы Windows Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
387
41
i Надоели баннеры? Вы всегда можете отключить рекламу.
i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Эффективные методы распределения памяти для операционной системы Windows»

ЭФФЕКТИВНЫЕ МЕТОДЫ РАСПРЕДЕЛЕНИЯ ПАМЯТИ ДЛЯ ОПЕРАЦИОННОЙ СИСТЕМЫ \VINDOWS

Н.В. ХАРЧЕНКО, аспирант кафедры ЭМТ МГУЛа

Управление памятью в операционной системе Windows

Каждый процесс, выполняющийся в операционной системе Windows, получает в свое распоряжение до 4 Гб виртуального адресного пространства. Такой объем памяти значительно превосходит объем физической памяти в реальных компьютерах. Для увеличения объема памяти операционная система использует файл подкачки, располагающийся на жестком диске компьютера. Задачей операционной системы является установка соответствия между виртуальным адресным пространством, с которым работает процесс, и физической памятью или файлом подкачки.

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

Страница в виртуальном адресном пространстве может находиться в одном из трех состояний:

1. Свободная страница.

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

3. Занятая страница. Для занятой страницы выделена страница в физической памяти или файле подкачки. Занятая страница может использоваться для хранения данных или кода программы. Для работы с виртуальным адресным пространством предназначены функции Virtual Alloc и

VirtualFree. Минимальный объем памяти, с которым работают эти функции, составляет одну страницу. С помощью функции Virtual Alloc можно производить следующие операции:

• Зарезервировать несколько идущих подряд свободных страниц.

• Занять несколько идущих подряд предварительно зарезервированных страниц.

• Занять несколько идущих подряд свободных страниц.

Функция VirtualFree позволяет совершать обратные операции:

• Освободить несколько идущих подряд зарезервированных страниц.

• Перевести несколько идущих подряд занятых страниц в зарезервированное состояние.

• Освободить несколько идущих подряд занятых страниц.

Описанные методы работы с виртуальным адресным пространством являются базовыми методами распределения памяти в операционной системе Windows. Все прочие методы распределения памяти реализованы через функции работы с виртуальным адресным пространством.

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

Стековый распределитель памяти

Рассмотрим один из методов быстрого распределения памяти и его реализацию в операционной системе Windows. Основная идея метода состоит в отказе от сложной обработки освобождения памяти и поиска места для выделения нового блока памяти. Все блоки памяти будем выделять в предварительно зарезервированном непрерывном участке памяти. Новые блоки памяти всегда будем выделять непосредственно за последним занятым участком памяти. Повторное использования освобождаемых участков памяти в предлагаемом методе не поддерживается.

Для реализации описываемого метода создадим C++ класс CStackAllocator. Объявление класса приводится ниже:

class CStackAllocator { public:

CStackAllocator( int reservedSize);

•CStackAllocator();

void* Alloc( int size ); private:

int commitedSize;

int allocatedSize;

char* buffer;

void commitNew(int newSize);

Объекты класса CStackAllocator содержат следующие поля данных:

• Указатель на начало используемого диапазона адресов в виртуальном адресном пространстве buffer.

• Размер использованного под занятые страницы диапазона адресов commitedSize.

• Размер уже использованного для выделения памяти участка буфера allocatedSize.

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

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

Класс CStackAllocator не содержит явного метода освобождения памяти. Все занятые страницы памяти освобождаются вместе при разрушении объекта - распределителя памяти.

Ниже приводится реализация методов класса CStackAllocator. Реализация использует константу PAGE_SIZE, которая должна быть равна размеру страницы памяти:

CStackAllocator:: CStackAllocator (int size ): commitedSize( 0), allocatedSize( 0) {

// Округляем размер резервируемого адресного пространства до // страницы

size = (size + PAGE_SIZE - 1) / PAGE„SIZE * PAGE_SIZE;

// Резервируем диапазон адресного пространства

buffer = (char*) VirtualAlloc( 0, size, MEM_RESERVE, PAGEJTOACCESS); }

CStackAllocator: :—CStackAllocator() {

// Освобождаем занятые страницы и зарезервированное адресное

// пространство

VirtualFree( buffer, О, MEM_RELEASE); } void* CStackAllocator: :Alloc( int size ) { char* ptr = buffer + allocatedSize; if( allocatedSize + size > commitedSize ) // Необходимо занять новые страницы commitNew( allocatedSize + size);

allocatedSize += size; return ptr; }

void CStackAllocator: :commitNew(int newSize) { newSize = (newSize + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE;

VirtualAlloc(buffer + commitedSize, newSize -commitedSize, MEM_COMMIT, PAGE_READWRITE); commitedSize = newSize;

}

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

Рассмотрим достоинства и недостатки предлагаемого механизма распределения памяти. Основных достоинств два:

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

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

Блоковый распределитель памяти

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

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

Описанный механизм работы с памятью реализован в блоковом распределителе памяти. При создании объекта-распределителя памяти ему указывается размер блока памяти. Каждый конкретный объект предназначен для работы с блоками памяти только указанного при создании размера. Распределитель памяти содержит односвязный список свободных блоков. В самом объекте хранится указатель на первый свободный блок. В начале каждого свободного блока хранится указатель на следующий свободный блок. Для последнего свободного блока этот указатель нулевой. Так как свободные блоки используются в качестве узлов односвязного списка, размер блока должен быть достаточен для хранения указателя, т.е. не быть меньше 4 байт.

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

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

class CBlockAllocator { public:

CBlockAllocator ( int blockSize, int allocator-Size ) ; void* Alloc ( ) ; void Free ( void* block } ; private:

void *firstFree; int blockSize; CStackAllocator allocator; }; CBlockAllocator : : CBlockAllocator (

int requiredBlockSize, int allocatorSize } : allocator (allocatorSize) {

// Список свободных блоков сначала пуст firstFree = 0;

// Вычисляем реальный размер блока Ыоск-Size = max (requiredBlockSize, sizeof (void*)); } void* CBlockAllocator: :Alloc() { if( firstFree \- 0) {

// Есть блок в списке свободных. // Возвращаем указатель на первый свободный блок void *ret = firstFree; firstFree = *( (void**) firstFree) ; return ret; } else {

// Выделяем новый блок в стековом распределителе памяти return allocator .Alloc (blockSize ); void CBlockAllocator: : Free ( void* block) {

// Добавляем освобождаемый блок в начало списка свободных блоков

* ((void**)block) = firstFree; firstFree = block;

}

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

Заключение

Каждый из описанных механизмов распределения памяти имеет как достоинст-

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

Литература

1. Platform SDK. Base Services. Memory. MSDN Library - October 2000.

2. Кнут Д. Искусство программирования для

ЭВМ. Основные алгоритмы, т.1 М.: Изд.

«Мир», 1976.

3. Бьярн Страуструп. Язык программирования C++. -Киев: «Диасофт» 1993.

ПРОБЛЕМА ВВОДА ФОРМУЛ В ЭВМ

Я.В. ЧЕЗГАНОВ, аспирант кафедры ПМ МГУJla

1. Введение

В настоящее время влияние информационных технологий на развитие науки неоспоримо. Ученые физики, математики, химики, биологи, экономисты активно используют компьютерные средства моделирования и проведения сложных математических расчетов. На ранке программного обеспечения существует целое направление систем «компьютерной математики», это такие известные системы, как МаШСас!, Ма1ЬаЬ, Мар1е, МаШетайса и другие. Обмен информацией между учеными разных стран часто происходит через интернет и другие средства глобальной коммуникации, то есть в электронном виде. Однако, хранение, передача и обработка информации в электронном виде возможны при условии её корректного и эффективного ввода в

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

Принципиально иначе обстоит дело с оцифровкой документов научного и технического содержания. И главной причиной тому - наличие в них формул.

2. Общий взгляд на проблему

Классическую схему1 процесса распознавания текста можно представить так, как это показано на схеме 1.

1 В настоящее время этой схемы придерживаются редко. Например, на этапе классификации может понадобиться возврат к предобработке.

i Надоели баннеры? Вы всегда можете отключить рекламу.