You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4.6 KiB

memory_pool (Object Pool Allocator)

1. Назначение

Быстрый аллокатор объектов фиксированного размера. Вместо постоянных malloc/free хранит до 64 освобождённых объектов в linked list для повторного использования. Применяется для hot-path объектов, которые часто создаются и уничтожаются: пакеты, фрагменты, ACK-пакеты, структуры маршрутизации, TCP-сегменты lwIP и т.д.

Встроенная защита:

  • Buffer overflow — канарейка 0xDEADBEAF после пользовательских данных проверяется при освобождении. При повреждении — бесконечный цикл (hang) для отладки.
  • Double free — однобайтный счётчик в метаданных; повторное освобождение детектируется и вызывает hang.
  • Вся диагностика пишется через DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, ...).

Не потокобезопасен — каждый пул используется из одного потока (обычно в рамках одного u_async event loop).

2. Как пользоваться

#include "memory_pool.h"

// 1. Создать пул (обычно в init-функции инстанса):
struct memory_pool* pkt_pool = memory_pool_init(sizeof(struct ETCP_DGRAM), "pkt_pool");

// 2. Выделить объект (если есть свободный — вернёт из пула, иначе u_calloc):
struct ETCP_DGRAM* dgram = memory_pool_alloc(pkt_pool);

// 3. Освободить объект (возвращается в пул, если там меньше 64 блоков):
memory_pool_free(pkt_pool, dgram);

// 4. Получить статистику:
size_t allocs, reuse;
memory_pool_get_stats(pkt_pool, &allocs, &reuse);
// reuse много → эффективно; reuse мало → пул слишком мал для нагрузки

// 5. Проверить, в пуле ли объект (0 — не в пуле, 1 — в пуле):
if (memory_pool_is_freed(pkt_pool, obj)) { /* уже освобождён */ }

// 6. Уничтожить пул (при shutdown):
memory_pool_destroy(pkt_pool);
// реально освобождает все кэшированные блоки через u_free() и сам пул.

Важно:

  • Если объекты пула используются как элементы ll_queue, в object_size нужно закладывать sizeof(struct ll_entry). Например: memory_pool_init(sizeof(struct ll_entry) + sizeof(struct dummynet_pkt), "pkt_pool").
  • memory_pool_alloc обнуляет объект перед возвратом (защита от утечки старых данных).
  • При заполнении пула (64 свободных блока) лишние memory_pool_free реально вызывают u_free — блок не кэшируется.
  • memory_pool_destroy проходит по всем свободным блокам и вызывает u_free для каждого, затем освобождает сам struct memory_pool.

3. API

Функция/макрос Описание
memory_pool_init(object_size, name) Создаёт пул для объектов заданного размера. name — для диагностики.
memory_pool_alloc(pool) Выделяет объект: из кэша (если есть) или через u_calloc. Обнуляет перед возвратом.
memory_pool_free(pool, obj) Возвращает объект в пул (до 64) или вызывает u_free. Проверяет canary и double-free.
memory_pool_destroy(pool) Уничтожает пул: освобождает все кэшированные блоки и сам пул.
memory_pool_get_stats(pool, &allocs, &reuse) Статистика: общее число аллокаций и число повторных использований из кэша.
memory_pool_get_total_free_blocks() Глобальный счётчик свободных блоков во всех пулах (для диагностики).
memory_pool_is_freed(pool, obj) Проверяет, находится ли объект в свободном списке пула (уже освобождён).