Программирование DSP VDK: пулы памяти Sat, April 20 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

VDK: пулы памяти Печать
Добавил(а) microsin   

Общие проблемы, связанные с выделением памяти через malloc, это как фрагментация кучи (heap), так и неопределенные затраты времени на поиск свободной области в куче при выделении блока памяти нужного размера. Как альтернатива malloc менеджер пула памяти использует заранее определенные пулы (Memory Pool), чтобы обеспечить эффективный, прогнозируемый во времени механизм выделения памяти. Использование пулов для выделения памяти может иметь особое преимущество, когда требуется много выделений и освобождений в памяти объектов одинакового размера.

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

Функционал пула памяти. Пулы можно создать либо во время загрузки и запуска приложения VDK (boot time), либо динамически вызовами API-функций CreatePool() или CreatePoolEx(). Когда создается пул памяти, указывается размер блока и количество блоков в пуле. Менеджер пула памяти выделяет память, необходимую для пула, и делит её на блоки во время создания, если это необходимо. VDK позволяет создавать блоки по запросу во время выполнения программы (при вызове MallocBlock()), вместо того, чтобы создавать блоки во время создания пула. При создании блоков по запросу уменьшаются затраты времени на создание пула, но зато увеличивается время на получение нового блока из пула. Дополнительно выделение и освобождений блока пула (вызовами FreeBlock() и LocateAndFreeBlock()) происходит предсказуемо по времени, если блоки пула созданы в момент создания пула.

Чтобы удовлетворять ограничениям по выравниванию данных в памяти, указанный размер блока внутренне округляется, так чтобы его размер составлял значение, нацело делимое на размер указателя в архитектуре (для Blackfin это 4 байта) - все адреса блоков, возвращенные MallocBlock(), делятся нацело на sizeof(void*).

Можно использовать API-вызовы GetNumAllocatedBlocks() и GetNumFreeBlocks(), чтобы определить в отдельном пуле количество используемых или доступных блоков соответственно.

[Когда имеется несколько куч]

По умолчанию все элементы VDK размещены в системной куче (heap), или в нескольких кучах.

Примечание: в зависимости от используемого процессора, VDK создает одну или две системные кучи. См. Приложение A, "Processor-Specific Notes", для информации по конкретным типам процессоров.

В предыдущих версиях VDK можно было использовать несколько куч при определении пулов памяти на процессорах, где предоставлена поддержка нескольких куч. Этот механизм был расширен, и VDK может теперь использовать несколько куч во время линковки (динамическое создание куч не разрешается), чтобы указать, какая область памяти используется для выделения различных элементов VDK (семафоры, сообщения, стеки потоков, и так далее). Разработчик отвечает за настройку куч. Дополнительную информацию по поводу того, как задать несколько куч, см. в руководстве "C/C++ Compiler and Library Manual" для Вашего целевого процессора.

Чтобы указать кучу VDK, создайте в среде VisualDSP++ новую кучу (у которой будет VDK HeapID). Затем с этим именем связывается идентификатор ID. Этот ID должен быть тем же самым, который используется в установки кучи во время выполнения кода C/C++ (идентификатор это целое число или строка, в зависимости от процессора). Дополнительную информацию по кучам VDK см. в online-документации.

[Локальное хранилище потока (Thread Local Storage)]

Локальное хранилище потока позволяет связать данные с потоками на базе каждого потока. Обычное использование этой функциональности вовлекает выделение области данных, требуемых отдельными потоками, с помощью потокобезопасной библиотечной функции (например, чтобы сохранить относящееся к потоку значение кода ошибки errno для каждого потока, что применяется в библиотеках времени выполнения языка C).

Для этой цели имеется 8 слотов локального хранилища потока. Перед тем, как значение будет сохранено в соответствующем слоте таблицы слотов потока должна быть выделена ячейка в глобальной таблице слотов путем использования вызова AllocateThreadSlot() или AllocateThreadSlotEx(). Если слот доступен в глобальной таблице, то соответствующий слот также резервируется в каждой таблице слотов потока. Эти вызовы API возвратят FALSE, если нет доступных свободных слотов. Выделенная ячейка в глобальной таблице слотов может быть впоследствии освобождена вызовом FreeThreadSlot(). Этот механизм выделения слотов предоставляет единовременную инициализацию слотов специфичных для потока данных, используемых библиотечными функциями. Слоты выделяются в таблице слотов каждого потока первым вызовом библиотечной функции, сделанном любым потоком.

Как только слот был выделен в глобальной таблице слотов, соответственное значение в таблице слотов отдельного потока может быть установлено вызовом SetThreadSlotValue(), сделанного из рассматриваемого потока. Значение имеет тип void*, и может использоваться для сохранения целого значения или указателя на выделенную память. Использование вызова AllocateThreadSlotEx() для выделения слота позволяет указать функцию очистки (cleanup function), которая вызывается при уничтожении потока, чтобы работать с динамически выделяемой памятью, которая связана со слотом потока. И наконец, можно использовать GetThreadSlotValue(), чтобы получить значение, сохраненное в таблице слотов отдельного потока.

[Ссылки]

1. VDK Memory Pools site:analog.com.

 

Добавить комментарий


Защитный код
Обновить

Top of Page