Управление памятью (виртуальная память и кучи). Лабораторная работа 2.


Лабораторная работа № 2

Управление памятью (виртуальная память и кучи)

Цель работы : знакомство с функциями Win32 и структурами данных, используемыми для управления памятью.

В Win32 три механизма управления памятью:

  • виртуальная память, используемая для операций с большими массивами объектов или структур;
  • кучи (heaps), применяемые для операций с большим количеством малых объектов;
  • файлы, проецируемые в память средства для операций с интенсивными потоками данных (обычно из файлов) и для обеспечения совместного доступа приложений к данным.

Функции и структуры данных управления виртуальной памятью

 

  1. Сведения о конкретной платформе предоставляет процедура:

GetSystemInfo (SYSTEM_INFO: TSystemInfo).

Структура данных TSystemInfo описана в файле Windows.pas cледующим образом:

TSystemInfo = record

case Integer of

0:  ( dwOemId: DWORD);

1:  (  wProcessorArchitecture: Word;

wReserved: Word;

dwPageSize: DWORD; // размер страницы

lpMinimumApplicationAddress: Pointer; //мин адрес доступного адресного пространства

lpMaximumApplicationAddress: Pointer; //макс адрес доступного адресного пространства

dwActiveProcessorMask: DWORD;

dwNumberOfProcessors: DWORD; // число процессоров

dwProcessorType: DWORD;

dwAllocationGranularity: DWORD; //    гранулярность выделения регионов адресного

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

wProcessorLevel: Word;

wProcessorRevision: Word);

end;

Более подробная информация приведена в файле Win32.hlp.

  1. Для динамического отслеживания текущего состояния памяти используется процедура

GlobalMemoryStatus(var lpBuffer: TMemoryStatus);

Структура данных TMemoryStatus описана в файле Windows.pas  cледующим образом:

TMemoryStatus = record

dwLength: DWORD;

dwMemoryLoad: DWORD; //оценка занятости системы управления памятью(0-100)

dwTotalPhys: DWORD;// общий размер физической памяти RAM-памяти в байтах

dwAvailPhys: DWORD;//  общий размер физической памяти RAM-памяти в

//  байтах, доступной для выделения

dwTotalPageFile: DWORD;// максимальное количество байтов, которое может

//  содержаться в страничном файде на жестком диске (или дисках)

dwAvailPageFile: DWORD;  // максимальное количество байтов, которое может быть

// передано процессу из страничного файла

dwTotalVirtual: DWORD;  // количество байтов в адресном пространстве, принадлежащих

// лично данному процессу

dwAvailVirtual: DWORD; // суммарный объем всех свободных регионов в адресном

//    пространстве процесса, вызывающего процедуру GlobalMemoryStatus

//    вычитая из dwTotalVirtual полученное значение, можно найти размер

//    зарезервированной процессом области в виртуальном адресном пространстве

end;

Перед вызовом процедуры необходимо занести в поле  dwLength размер структуры в байтах с помощью функции sizeof().

  1. Для запроса информации об участке памяти по заданному адресу (размер, тип памяти, атрибуты защиты) служит функция:

VirtualQuery(lpAddress: Pointer;

var lpBuffer: TMemoryBasicInformation; dwLength: DWORD): DWORD;

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

Второй параметр – переменная типа, описанного как

TMemoryBasicInformation = record

BaseAddress : Pointer;  // значение параметра lpAddress, округленное до значения,

// кратного размеру страницы

AllocationBase : Pointer; // базовый адрес региона, включающего адрес запроса

AllocationProtect : DWORD; // атрибут защиты региона – в Win 9х  может иметь

// значения PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE

RegionSize : DWORD;// суммарный размер (в байтах) группы страниц, начинающихся с

// базового адреса и имеющих те же атрибуты защиты, состояние и тип, что и страница,

// обнаруженная по адресу lpAddress

State : DWORD;  //указывает состояние (MEM_FREE,MEM_RESERVE,MEM_COMMIT) всех

// смежных  страниц,имеющих те же атрибуты защиты,состояние и тип, что и страница,

//   расположенная по адресу lpAddress

// Числовые значения констант состояния приведены в файле windows.pas

// Для состояния MEM_FREE элементы Allocationbase, Alloocation, Protect и Type  не

//  определяются

Protect : DWORD;   //содержит атрибут защиты (PAGE_*),общий для всех смежных страниц,

// имеющих те же атрибуты защиты, состояние и тип, что и страница, расположенная по

// адресу lpAddress

Type_9 : DWORD;  //определяет тип физической памяти (MEM_IMAGE,MEM_MAPPED или

// MEM_PRIVATE), связанной с группой смежных страниц, имеющих имеющих те же атрибуты

// защиты,состояние и тип, что и страница, расположенная по адресу lpAddress

// В Win 9x этот элемент всегда соответствует типу MEM_PRIVATE

end;

Параметр dwLength задает размер структуры TmemoryBasicInformation.

VirtualQuery возвращает число байт, скопированных в буфер. Если возвращено нулевое значение, информация о запрошенном участке НЕ ПОЛУЧЕНА.

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

  1. Приложение резервирует регион в адресном пространстве, используя  функцию

VirtualAlloc(lpvAddress: Pointer; dwSize, flAllocationType, flProtect: DWORD):   Pointer;

Первый параметр определяет положение резервируемого региона в адресном пространстве. Если параметр равен Nil, система определяет положение региона самостоятельно. В Win 9x зарезервировать регион  можно только в диапазоне адресов от  00400000Н до 7FFFFFFFH. Регионы всегда резервируются на границе 64К.

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

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

Третий параметр определяет вид операции – MEM_RESERVE –зарезервировать регион, MEM_COMMIT-  передать региону физическую память (сначала нужно зарезервировать регион, затем передать ему память).

В принципе можно одновременно зарезервировать регион и передать ему физическую память – например

VirtualAlloc (Nil, 100*1024,MEM_RESERVE  OR MEM_COMMIT,PAGE_READWRITE);

Последний параметр определяет атрибут защиты.

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

VirtualFree (lpAddress: Pointer; dwSize,: DWORD): BOOL;

В простейшем случае использования этой функции – для освобождения всей переданной региону физической памяти – в параметр lpAddress необходимо передать базовый адрес региона, в параметр dwSize=0, так как системе известен размер региона. В третьем параметре следует передать MEM_RELEASE –это приведет к возврату системе всей физической памяти, спроецированной на регион, и освобождению самого региона. Если необходимо не освобождая регион вернуть в систему часть физической памяти, переданной региону, в параметр lpAddress заносится адрес, идентифицирующий первую возвращаемую страницу, в параметр dwSize – количество возвращаемых байт, в параметре dwFreeType — MEM_DECOMMIT.

КУЧИ

Процессу разрешено создавать несколько куч, являющихся частью его адресного пространства.

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

Одна куча предоставляется процессу по умолчанию. Ее описатель возвращает функция

GetProcessHeap() : Handle;

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

HeapCreate ( flOption, dwInitialSize, MaximumSize) : Handle;

Первый параметр определяет характер операций, выполняемых над кучей. По умолчанию (значение 0) действует принцип последовательного доступа к куче (как к критическому участку).

САМОСТОЯТЕЛЬНО

—  другие возможные значения этого параметра и их использование.

Второй параметр определяет количество байт, первоначально передаваемых куче.

Третий параметр указывает максимальный размер кучи. Может быть равен 0 — в этом случае система резервирует регион, самостоятельно определяя его размер и при необходимости расширяет его до максимально возможного объема.

Выделение блока памяти из кучи  выполняет функция

HeapAlloc ( Handle, dwFlags, dwBytes ) : pointer;

Первый параметр — описатель кучи, возвращаемый функциями GetProcessHeap() или HeapCreate()

Второй параметр указывает на характер выделения памяти. При его значении, равным HEAP_ZERO_MEMORY, выделяемый блок заполняется нулями.

Третий параметр определяет число выделяемых в куче байт.

Освобождение блока памяти   выполняет функция

HeapFree ( Handle, dwFlags, dwBytes ) : Boolean;

Уничтожение кучи выполняет функция  HeapDestroy (Handle) : Boolean.

Значения символических констант для операций с кучами:

HEAP_NO_SERIALIZE               0x00000001

HEAP_GROWABLE                   0x00000002

HEAP_GENERATE_EXCEPTIONS        0x00000004

HEAP_ZERO_MEMORY                0x00000008

HEAP_REALLOC_IN_PLACE_ONLY      0x00000010

HEAP_TAIL_CHECKING_ENABLED      0x00000020

HEAP_FREE_CHECKING_ENABLED      0x00000040

HEAP_DISABLE_COALESCE_ON_FREE   0x00000080

HEAP_CREATE_ALIGN_16            0x00010000

HEAP_CREATE_ENABLE_TRACING      0x00020000

HEAP_MAXIMUM_TAG                0x0FFF

HEAP_PSEUDO_TAG_FLAG            0x8000

HEAP_TAG_SHIFT                  18

ВЫПОЛНЕНИЕ РАБОТЫ

  1. Написать приложение, реализующие следующие функции:
  • 1 — вывод на экран системной информации;
  • 2 — мониторинг состояния разделов виртуальной памяти 0-1 Гб, 1-2 Гб, 2-3 Гб  (показатели общий объем свободной, зарезервированной и выделенной -commit- памяти, а также памяти, состояние которой не было определено). По каждому разделу выводить предыдущее, текущее значение каждого показателя и их разность;
  • 3 — свободной страничной памяти с выводом результатов на экран с интервалом 3 с;
  • 4 — резервирование региона задаваемого размера с размещением с задаваемого адреса (по кнопке);
  • 5 — резервирование региона задаваемого размера с без указания адреса (по кнопке);
  • 6 — проецирование физической памяти задаваемого размера на регион (по кнопке);
  • 7 — возврат системе физической памяти из выбранного региона (по кнопке);
  • 8 — освобождение региона ( по кнопке);
  • 9 — запуск приложения с возможностью диалогового выбора его имени;
  • 10 — размещение в куче процесса по умолчанию списка из N cлов (по кнопке);
  • 11 — cоздание кучи и размещение в ней списка из M элементов по 20 байт в каждом (по кнопке).
  1. Проверить работу приложения. Обратить внимание на изменение размера раздела в виртуальном адресном пространстве процесса после резервирования, освобождения региона, запуска и завершения приложения, размещения списков.
  1. Ответить на вопросы:
  • в каких регионах выделялась память и какого размера;
  • размер какого региона изменился после запуска и завершения приложения. Сопоставить эти значения с размером exe-файла приложения.
  • следует ли ожидать изменений в разделах виртуального адресного пространства после запуска того же приложения с помощью проводника?
  • как отразилось на состоянии разделов виртуальной памяти размещение списков в кучах?

ОТЧЕТ О РАБОТЕ

  1. Демонстрация экранных форм разработанного приложения.
  2. В ПИСЬМЕННОМ виде:
  • системная информация – название параметра и его значение;

ответы на вопросы  п.3.