Справочник Ada 95
13.11 Управление памятью
Каждый тип доступа к объекту имеет связанный пул памяти. Память, выделенная аллокатором, берётся из пула; экземпляры Unchecked_Deallocation возвращают память в пул. Несколько типов доступа могут использовать один и тот же пул.
Пул памяти — это переменная типа, унаследованная от Root_Storage_Pool, который является абстрактным ограниченным управляемым типом. По умолчанию реализация выбирает стандартный пул памяти для каждого типа доступа. Пользователь может определять новые типы пулов и может переопределять выбор пула для типа доступа, указав Storage_Pool для типа.
Правила законности
Если для данного типа доступа указан Storage_Pool, то Storage_Size для него не должен быть указан.
Статическая семантика
Существует следующий определённый языком пакет библиотеки:
with Ada.Finalization;
with System.Storage_Elements;
package System.Storage_Pools is
pragma Preelaborate(System.Storage_Pools);
with System.Storage_Elements;
package System.Storage_Pools is
pragma Preelaborate(System.Storage_Pools);
type Root_Storage_Pool is
abstract new Ada.Finalization.Limited_Controlled with private;
abstract new Ada.Finalization.Limited_Controlled with private;
procedure Allocate(
Pool : in out Root_Storage_Pool;
Storage_Address : out Address;
Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
Alignment : in Storage_Elements.Storage_Count) is abstract;
Pool : in out Root_Storage_Pool;
Storage_Address : out Address;
Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
Alignment : in Storage_Elements.Storage_Count) is abstract;
procedure Deallocate(
Pool : in out Root_Storage_Pool;
Storage_Address : in Address;
Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
Alignment : in Storage_Elements.Storage_Count) is abstract;
Pool : in out Root_Storage_Pool;
Storage_Address : in Address;
Size_In_Storage_Elements : in Storage_Elements.Storage_Count;
Alignment : in Storage_Elements.Storage_Count) is abstract;
function Storage_Size(Pool : Root_Storage_Pool)
return Storage_Elements.Storage_Count is abstract;
return Storage_Elements.Storage_Count is abstract;
private
... -- не указано языком
end System.Storage_Pools;
... -- не указано языком
end System.Storage_Pools;
Тип пула памяти (или тип пула) — это потомок Root_Storage_Pool. Элементы пула памяти — это объекты, выделенные в пуле аллокаторами.
Для каждого подтипа доступа S определены следующие атрибуты представления:
- S'Storage_Pool
- Обозначает пул памяти типа S. Тип этого атрибута — Root_Storage_Pool'Class.
- S'Storage_Size
- Возвращает результат вызова Storage_Size(S'Storage_Pool), который предназначен для измерения количества элементов памяти, зарезервированных для пула. Тип этого атрибута — universal_integer.
Storage_Size или Storage_Pool могут быть указаны для непроизводного типа доступа к объекту с помощью описания_атрибута; имя в Storage_Pool должно указывать на переменную.
Аллокатор типа T выделяет память из пула памяти T. Если пул памяти — это пользовательский объект, то память выделяется путём вызова Allocate, передавая T'Storage_Pool в качестве параметра Pool. Параметр Size_In_Storage_Elements указывает количество элементов памяти, которые необходимо выделить, и не превышает D'Max_Size_In_Storage_Elements, где D — обозначенный подтип. Параметр Alignment — D'Alignment. Результат, возвращённый в параметре Storage_Address, используется аллокатором как адрес выделенной памяти, которая представляет собой непрерывный блок памяти размером Size_In_Storage_Elements элементов памяти. Любое исключение, распространяемое Allocate, распространяется аллокатором.
Если Storage_Pool не указан для типа, определённого определением_доступа_к_объекту, то реализация выбирает стандартный пул памяти для него способом, определённым реализацией. В этом случае исключение Storage_Error генерируется аллокатором, если памяти недостаточно. Определяется реализацией, предоставляет ли она пользователю доступные имена для типа(ов) стандартного пула.
Если Storage_Size указан для типа доступа, то Storage_Size этого пула не меньше запрошенного, а память пула возвращается, когда главный блок, содержащий объявление типа доступа, покинут. Если реализация не может удовлетворить запрос, Storage_Error генерируется в точке описания_атрибута. Если ни Storage_Pool, ни Storage_Size не указаны, то значение Storage_Size определяется реализацией.
Если для типа доступа указан Storage_Pool, используется указанный пул.
Эффект вызова Allocate и Deallocate для стандартного пула памяти непосредственно (а не неявно через аллокатор или экземпляр Unchecked_Deallocation) не определён.
Ошибочное выполнение
Если для типа доступа указан Storage_Pool, то если Allocate может удовлетворить запрос, он должен выделить непрерывный блок памяти и вернуть адрес первого элемента памяти в Storage_Address. Блок должен содержать Size_In_Storage_Elements элементов памяти и должен быть выровнен в соответствии с Alignment. Выделенная память не должна использоваться для других целей, пока элемент пула существует. Если запрос не может быть удовлетворён, Allocate должен распространить исключение (например, Storage_Error). Если Allocate ведёт себя каким-либо иным образом, выполнение программы является ошибочным.
Требования к документации
Реализация должна документировать набор значений, которые должен принимать пользовательский процедура Allocate для параметра Alignment. Реализация должна документировать, как выбирается стандартный пул памяти и как выделяется память стандартными пулами памяти.
Рекомендации по реализации
Реализация должна документировать любые случаи, когда она динамически выделяет память кучи для целей, отличных от оценки аллокатора.
Стандартный (предоставленный реализацией) пул памяти для типа доступа к константе не должен иметь накладных расходов для поддержки освобождения отдельных объектов.
Пул памяти для анонимного типа доступа должен создаваться в момент аллокации для типа и возвращаться, когда целевой объект становится недоступным.
ПРИМЕЧАНИЯ
23 Пользовательский тип пула памяти может быть получен путём расширения типа Root_Storage_Pool и переопределения примитивных подпрограмм Allocate, Deallocate и Storage_Size. Затем пользовательский пул памяти можно получить, объявив объект типа расширения. Пользователь может переопределить Initialize и Finalize, если требуется нетривиальная инициализация и завершение работы для пользовательского типа пула. Например, Finalize может освободить блоки памяти, выделенные отдельно от самого объекта пула.
24 Автор пользовательских процедур выделения и освобождения и пользователи аллокаторов для соответствующего типа доступа несут ответственность за взаимодействие с задачами. В частности:
- Если аллокаторы используются в разных задачах, они требуют взаимного исключения.
- Если они используются внутри защищённых объектов, они не могут блокироваться.
- Если они используются обработчиками прерываний (см. C.3, «Поддержка прерываний»), механизм взаимного исключения должен работать должным образом в этом контексте.
25 Примитивы Allocate, Deallocate и Storage_Size объявлены абстрактными (см. 3.9.3), и поэтому они должны быть переопределены при объявлении нового (не абстрактного) типа пула памяти.
Примеры
Чтобы связать тип доступа с объектом пула памяти, пользователь сначала объявляет объект пула некоторого типа, полученного от Root_Storage_Pool. Затем пользователь определяет его атрибут Storage_Pool следующим образом:
Pool_Object : Some_Storage_Pool_Type;
type T is access Designated;
for T'Storage_Pool use Pool_Object;
for T'Storage_Pool use Pool_Object;
Другой тип доступа может быть добавлен в существующий пул памяти следующим образом:
for T2'Storage_Pool use T'Storage_Pool;
Семантика этого определена реализацией для стандартного пула памяти.
Как обычно, производный тип Root_Storage_Pool может определять дополнительные операции. Например, предположим, что Mark_Release_Pool_Type имеет две дополнительные операции, Mark и Release, следующее является возможным использованием:
type Mark_Release_Pool_Type
(Pool_Size : Storage_Elements.Storage_Count;
Block_Size : Storage_Elements.Storage_Count)
is new Root_Storage_Pool with private;
(Pool_Size : Storage_Elements.Storage_Count;
Block_Size : Storage_Elements.Storage_Count)
is new Root_Storage_Pool with private;
...
MR_Pool : Mark_Release_Pool_Type (Pool_Size => 2000,
Block_Size => 100);
Block_Size => 100);
type Acc is access ...;
for Acc'Storage_Pool use MR_Pool;
...
for Acc'Storage_Pool use MR_Pool;
...
Mark(MR_Pool);
... -- Выделить объекты с помощью ``new Designated(...)''.
Release(MR_Pool); -- Освободить память.
... -- Выделить объекты с помощью ``new Designated(...)''.
Release(MR_Pool); -- Освободить память.