Руководство по языку B.Pascal 7

       

Администратор динамически распределяемой области памяти DOS


Динамически распределяемая область - это похожая на стек структура, которая увеличивается, начиная от младших адресов па- мяти. При этом используется сегмент динамически распределяемой области. Нижняя граница динамически распределяемой области запо- минается в переменной HеаpOrg, а верхняя граница динамически распределяемой области соответствует нижней границе свободной па- мяти и сохраняется в переменной НеаpPtr. При каждом выделении ди- намической переменной в динамически распределяемой области под- система динамического распределения памяти (администратор динами- чески распределяемой области) перемещает переменную HeapPtr вверх на размер переменной, как бы организуя при этом стек динамических переменных, в котором одна переменная размещается над другой.

Переменная НеаpPtr после каждой операции как правило норма- лизуется, и смещение, таким образом, принимает значения в диапа- зоне от $0000 до $000F. Так как каждая переменная должна целиком содержаться в одном сегменте, максимальный размер отдельной пере- менной, которая может быть размещена в динамически распределяемой области, составляет 65521 байт (что соответствует $10000 минус $000F).


Расширения Borland защищенного режима DOS включают в себя полный администратор памяти защищенного режима. При выполнении программы защищенного режима DOS вся доступная память превращает- ся в глобальную динамически распределяемую область памяти, кото- рая управляется администратором памяти (подсистемой управления памятью) защищенного режима. Прикладная программа может получить доступ к глобальной динамически распределяемой области памяти че- рез подпрограммы GlobalXXXX модуля WinAPI. Хотя можно распреде- лять блоки глобальной памяти любого размера, глобальная динами- чески распределяемая область памяти предназначена только для больших блоков (1024 байт или более). Для каждого блока глобаль- ной памяти требуется дополнительно 32 байта (это непроизводитель- ные затраты), а общее число блоков глобальной памяти не может превышать 8192.

Примечание: Подробнее расширения Borland защищенного режима DOS описываются в Главе 17 "Программирование в защи- щенном режиме DOS".

Borland Pascal включает в себя администратор памяти (который называют также подсистемой управления памятью), реализующий стан- дартные процедуры New, Dispose, GetMem и FreeMem. Администратор памяти использует для всех распределений памяти глобальную дина- мически распределяемую область. Поскольку глобальная динамически распределяемая область памяти ограничена 8192 блоками (что оче- видно меньше, чем может потребоваться для некоторых прикладных программ), администратор памяти Borland Pascal реализует алгоритм вторичного распределения сегментов, который улучшает производи- тельность и допускает распределение существенно большего коли- чества блоков.

Примечание: Borland Pascal для расширенного режима DOS не поддерживает схему распределения с помощью процедур MArk и Release, предусмотренную для реального режима DOS.

Алгоритм вторичного распределения блоков работает следующим образом. При выделении большого блока администратор памяти просто выделяет глобальную память с помощью подпрограммы GlobalAlloc. При выделении маленького блока администратор выделяет более круп- ный блок памяти, а затем разбивает его (вторично распределяет) по требованию на более мелкие блоки. Перед тем, как администратор памяти выделяет новый блок глобальной памяти, который, в свою очередь, будет распределяться повторно, при распределении малень- ких блоков повторно используется все доступное пространство вто- ричного распределения.




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

Примечание: Более подробно о локальной и глобальной динамически распределяемой области рассказывается в "Руко- водстве программиста по Windows".

Глобальная динамически распределяемая область - это пул па- мяти, доступный для всех прикладных программ. Хотя могут выде- ляться блоки глобальной памяти любого размера, глобальная динами- чески распределяемая область памяти предназначена только для "больших" областей памяти (256 байт или более). Каждый блок гло- бальной памяти имеет избыточный размер 20 байт, и при работе в стандартной среде Windows в улучшенном режиме 386 существует ог- раничение в 8192 блока памяти, только некоторые из которых дос- тупны для отдельной прикладной программы.

Локальная динамически распределяемая область памяти - это пул памяти, доступной только для вашей прикладной программы или библиотеки. Она расположена в верхней части сегмента данных прик- ладной программы или библиотеки. Общий размер блоков локальной памяти, которые могут выделяться в локальной динамически распре- деляемой области, равен 64К, минус размер стека прикладной прог- раммы и статических данных. По этой причине локальная динамически распределяемая область памяти лучше подходит для "небольших" бло- ков памяти (26 байт или менее). По умолчанию размер локальной ди- намически распределяемой области равен 8К, но с помощью директивы компилятора $M это значение можно изменить.

Примечание: Borland Pascal не поддерживает механизм распределения памяти с помощью процедур Mark и Release, ко- торые предусмотрены в версии для DOS.

Borland Pascal включает в себя подсистему управления динами- чески распределяемой памятью (администратор памяти), которая реа- лизует стандартные процедуры New, Dispose, GetMem и FreeMem. Для всех выделений памяти подсистема динамически управления распреде- ляемой областью памяти использует глобальную динамически распре- деляемую область. Поскольку глобальная динамически распределяемая область памяти имеет системное ограничение в 8192 блока (что оп- ределенно меньше, чем может потребоваться в некоторых прикладных задачах), подсистема управления динамически распределяемой об- ластью памяти Borland Pascal для улучшения производительности и обеспечения выделения существенно большего числа блоков включает в себя алгоритм вторичного распределения сегмента.




Примечание: Об использовании администратора памяти в DLL подробнее рассказывается в Главе 11 "Динамически компо- нуемые библиотеки".

Переменная HeapLimit определяет порог между маленькими и большими блоками динамически распределяемой памяти. По умолчанию ее значение равно 1024 байтам. Переменная HeapBlock определяет размер, используемый администратором памяти при распределении блоков, выделенных для вторичного распределения. По умолчанию значение HeapBlock равно 8192 байтам. Значения этих переменных изменять не следует, но если вы это сделаете, убедитесь, что зна- чение HeapBlock составляет не меньше четырехкратного размера HeapLimit.

Переменная HeapAllocFpals определяет значение флагов атрибу- тов, передаваемых GlobalAlloc, когда администратор памяти распре- деляет блоки глобальной памяти. По умолчанию ее значение равно gmem_Moveable.



Примечание: Более подробно об этом рассказывается в Главе 11 "Динамически компонуемые библиотеки".

Алгоритм вторичного выделения сегмента работает следующим образом: при распределении большого блока администратор динами- чески распределяемой области памяти просто выделяет глобальный блок памяти, используя подпрограмму Windows ClobalAlloc. При вы- делении маленького блока администратор динамически распределяемой области памяти выделяет больший блок памяти, а затем делит его на более мелкие блоки (как требуется). При выделении "маленьких" блоков перед тем, как администратор динамически распределяемой области памяти выделит блок глобальной динамически распределяемой памяти (который будет в свою очередь разбит на блоки), повторно используются все доступные мелкие блоки.

Границу между маленькими и большими блоками определяется пе- ременной HeapLimit. По умолчанию она имеет значение 1024 байта. Переменная HeapBlock определяет размер, который использует под- система управления динамически распределяемой областью памяти при выделении блоков для вторичного разбиения. По умолчанию она имеет значение 8192 байта. Изменять эти значения вам незачем, но если вы решите это сделать, убедитесь что HeapBlock имеет значение по крайней мере в четыре раза превышающее HeapLimit.

Переменная HeapAllocFlags определяет значение флагов атрибу- тов, передаваемых GlobalAlloc, когда администратор памяти распре- деляет глобальные блоки. В программе по умолчанию используется значение gmem_Moveable, а в библиотеке - gmem_Moveable + gmem_SSEShure.

Блоки глобальной памяти, выделяемые администратором динами- чески распределяемой области памяти, всегда блокируются непос- редственно после своего выделения (с помощью GlobalLock) немед- ленно после своего выделения и не разблокируются, пока не будут освобождены. Этим обеспечивается, что селекторы (адреса сегмен- тов) блоков не изменяются. В стандартной среде Windows и улучшен- ных режимах процессора 386 фиксированные блоки могут, тем не ме- нее, перемещаться в физической памяти, освобождая место для дру- гих запросов по выделению памяти, поэтому это не ухудшает произ- водительности администратора динамически распределяемой области памяти Borland Pascal. Однако в реальном режиме, если от Windows требуется расширение локальной динамически распределяемой облас- ти, администратор памяти Windows, возможно, не сможет переместить их, чтобы выделить другие блоки. Если ваша прикладная программа использует локальную динамически распределяемую область и должна выполняться в реальном режиме, можно рассмотреть при выделении блоков динамической памяти возможность использования средств распределения памяти, предоставляемых Windows.


Содержание раздела