内存管理系统针对视频摄像头大数据包场景
·
采用大块内存池 + mmap映射的管理方式。
一、整体架构设计
memory_manager/ ├── include/ │ ├── mem_core.h # 核心内存管理接口 │ ├── mem_pool.h # 小内存池管理 │ ├── mem_mmap.h # 大块MMAP管理 │ └── mem_video.h # 视频帧专用管理 ├── src/ │ ├── mem_core.c │ ├── mem_pool.c │ ├── mem_mmap.c │ └── mem_video.c └── test/ └── test_memory.c
二、核心内存管理接口设计
/**
* @file mem_core.h
* @brief 核心内存管理接口
* @details 提供统一的内存分配和释放接口,支持不同内存管理策略
*/
#ifndef MEM_CORE_H
#define MEM_CORE_H
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
/*==================== 内存块类型定义 ====================*/
/**
* @brief 内存块类型枚举
*/
typedef enum {
MEM_TYPE_SMALL_POOL, /*!< 小内存池管理 */
MEM_TYPE_MMAP_BLOCK, /*!< MMAP大块内存 */
MEM_TYPE_VIDEO_FRAME, /*!< 视频帧专用 */
MEM_TYPE_DMA_BUFFER /*!< DMA缓冲区 */
} mem_type_t;
/**
* @brief 内存块头部信息
* @details 每个内存块前都带有此头部,用于管理
*/
typedef struct mem_header {
uint32_t magic; /*!< 魔数,用于校验 */
mem_type_t type; /*!< 内存类型 */
uint32_t size; /*!< 数据区大小 */
uint32_t block_size; /*!< 实际分配大小(含头部)*/
struct mem_header *next; /*!< 链表下一节点 */
struct mem_header *prev; /*!< 链表上一节点 */
uint32_t ref_count; /*!< 引用计数 */
uint32_t flags; /*!< 标志位 */
/* 统计信息 */
uint64_t alloc_time; /*!< 分配时间戳 */
void *owner; /*!< 所有者标识 */
const char *file; /*!< 分配文件名 */
int line; /*!< 分配行号 */
} mem_header_t;
#define MEM_MAGIC 0xDEADBEEF
#define MEM_HEADER_SIZE sizeof(mem_header_t)
/*==================== 内存管理器接口 ====================*/
/**
* @brief 内存管理器虚函数表
*/
typedef struct mem_ops {
void* (*alloc)(void *manager, uint32_t size, uint32_t align);
void (*free)(void *manager, void *ptr);
void* (*realloc)(void *manager, void *ptr, uint32_t new_size);
void (*dump)(void *manager);
uint32_t (*get_used)(void *manager);
uint32_t (*get_total)(void *manager);
} mem_ops_t;
/**
* @brief 内存管理器基类
*/
typedef struct mem_manager {
const char *name; /*!< 管理器名称 */
mem_ops_t *ops; /*!< 操作函数表 */
void *private_data; /*!< 私有数据 */
uint32_t total_size; /*!< 总管理内存大小 */
uint32_t used_size; /*!< 已用内存大小 */
uint32_t peak_used; /*!< 峰值使用 */
} mem_manager_t;
/* 核心API */
void* mem_alloc(mem_manager_t *mgr, uint32_t size);
void* mem_alloc_align(mem_manager_t *mgr, uint32_t size, uint32_t align);
void mem_free(mem_manager_t *mgr, void *ptr);
void* mem_realloc(mem_manager_t *mgr, void *ptr, uint32_t new_size);
/* 调试辅助 */
#define MEM_ALLOC(mgr, size) mem_alloc_debug(mgr, size, __FILE__, __LINE__)
#define MEM_FREE(mgr, ptr) mem_free_debug(mgr, ptr, __FILE__, __LINE__)
#endif /* MEM_CORE_H */
/**
* @file mem_core.c
* @brief 核心内存管理实现
*/
#include "mem_core.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
/**
* @brief 通用内存分配接口
*/
void* mem_alloc(mem_manager_t *mgr, uint32_t size) {
if (!mgr || !mgr->ops || !mgr->ops->alloc) {
return NULL;
}
return mgr->ops->alloc(mgr->private_data, size, 4);
}
/**
* @brief 对齐内存分配
*/
void* mem_alloc_align(mem_manager_t *mgr, uint32_t size, uint32_t align) {
if (!mgr || !mgr->ops || !mgr->ops->alloc) {
return NULL;
}
return mgr->ops->alloc(mgr->private_data, size, align);
}
/**
* @brief 带调试信息的内存分配
*/
void* mem_alloc_debug(mem_manager_t *mgr, uint32_t size,
const char *file, int line) {
mem_header_t *header;
void *ptr;
ptr = mgr->ops->alloc(mgr->private_data, size + MEM_HEADER_SIZE, 8);
if (!ptr) return NULL;
header = (mem_header_t*)ptr;
header->magic = MEM_MAGIC;
header->size = size;
header->block_size = size + MEM_HEADER_SIZE;
header->file = file;
header->line = line;
struct timeval tv;
gettimeofday(&tv, NULL);
header->alloc_time = tv.tv_sec * 1000000 + tv.tv_usec;
mgr->used_size += header->block_size;
if (mgr->used_size > mgr->peak_used) {
mgr->peak_used = mgr->used_size;
}
return (void*)((uint8_t*)ptr + MEM_HEADER_SIZE);
}
/**
* @brief 带调试信息的内存释放
*/
void mem_free_debug(mem_manager_t *mgr, void *ptr,
const char *file, int line) {
mem_header_t *header;
void *real_ptr;
if (!ptr) return;
real_ptr = (void*)((uint8_t*)ptr - MEM_HEADER_SIZE);
header = (mem_header_t*)real_ptr;
if (header->magic != MEM_MAGIC) {
fprintf(stderr, "Memory corruption detected at %s:%d\n",
file, line);
return;
}
mgr->used_size -= header->block_size;
mgr->ops->free(mgr->private_data, real_ptr);
}
三、小内存池管理
/**
* @file mem_pool.h
* @brief 小内存池管理器
* @details 针对频繁分配的小内存块,预分配大块内存池
*/
#ifndef MEM_POOL_H
#define MEM_POOL_H
#include "mem_core.h"
/*==================== 内存池配置 ====================*/
#define POOL_MAX_LEVELS 8 /*!< 最大内存块等级 */
#define POOL_MIN_BLOCK_SIZE 32 /*!< 最小块大小 */
#define POOL_MAX_BLOCK_SIZE 4096 /*!< 最大块大小 */
/**
* @brief 内存池块信息
*/
typedef struct pool_block {
struct pool_block *next; /*!< 空闲链表指针 */
uint32_t size; /*!< 块大小 */
uint32_t magic; /*!< 魔数 */
} pool_block_t;
/**
* @brief 内存池等级
*/
typedef struct pool_level {
uint32_t block_size; /*!< 该等级块大小 */
uint32_t block_count; /*!< 块总数 */
uint32_t free_count; /*!< 空闲块数 */
pool_block_t *free_list; /*!< 空闲块链表 */
void *blocks_start; /*!< 块区域起始 */
} pool_level_t;
/**
* @brief 内存池管理器
*/
typedef struct mem_pool_manager {
mem_manager_t base; /*!< 基类 */
/* 内存池区域 */
void *pool_memory; /*!< 整个内存池起始 */
uint32_t pool_size; /*!< 内存池总大小 */
/* 等级管理 */
pool_level_t levels[POOL_MAX_LEVELS];
uint32_t level_count;
/* 统计 */
uint32_t alloc_count;
uint32_t free_count;
uint32_t fail_count;
/* 锁 */
void *lock;
} mem_pool_manager_t;
/**
* @brief 创建内存池管理器
* @param total_size 内存池总大小
* @return 内存管理器指针
*/
mem_manager_t* mem_pool_create(uint32_t total_size);
/**
* @brief 销毁内存池管理器
*/
void mem_pool_destroy(mem_manager_t *mgr);
#endif /* MEM_POOL_H */
/**
* @file mem_pool.c
* @brief 小内存池管理实现
*/
#include "mem_pool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* 私有操作函数声明 */
static void* pool_alloc(void *mgr, uint32_t size, uint32_t align);
static void pool_free(void *mgr, void *ptr);
static void pool_dump(void *mgr);
static uint32_t pool_get_used(void *mgr);
static uint32_t pool_get_total(void *mgr);
/* 操作函数表 */
static mem_ops_t pool_ops = {
.alloc = pool_alloc,
.free = pool_free,
.dump = pool_dump,
.get_used = pool_get_used,
.get_total = pool_get_total
};
/**
* @brief 初始化内存池等级
*/
static void init_pool_levels(mem_pool_manager_t *mgr) {
uint32_t size = POOL_MIN_BLOCK_SIZE;
uint32_t remaining = mgr->pool_size;
uint8_t *mem_ptr = (uint8_t*)mgr->pool_memory;
int level = 0;
while (size <= POOL_MAX_BLOCK_SIZE && level < POOL_MAX_LEVELS) {
pool_level_t *lvl = &mgr->levels[level];
uint32_t block_count = remaining / (size + sizeof(pool_block_t));
if (block_count > 0) {
lvl->block_size = size;
lvl->block_count = block_count;
lvl->free_count = block_count;
lvl->free_list = NULL;
lvl->blocks_start = mem_ptr;
/* 初始化空闲链表 */
pool_block_t *prev = NULL;
for (uint32_t i = 0; i < block_count; i++) {
pool_block_t *block = (pool_block_t*)mem_ptr;
block->next = NULL;
block->size = size;
block->magic = MEM_MAGIC;
if (prev) {
prev->next = block;
} else {
lvl->free_list = block;
}
prev = block;
mem_ptr += size + sizeof(pool_block_t);
}
remaining -= block_count * (size + sizeof(pool_block_t));
level++;
}
size *= 2; /* 每次翻倍 */
}
mgr->level_count = level;
}
/**
* @brief 创建内存池管理器
*/
mem_manager_t* mem_pool_create(uint32_t total_size) {
mem_pool_manager_t *mgr;
mgr = (mem_pool_manager_t*)malloc(sizeof(mem_pool_manager_t));
if (!mgr) return NULL;
memset(mgr, 0, sizeof(mem_pool_manager_t));
/* 分配整个内存池 */
mgr->pool_memory = malloc(total_size);
if (!mgr->pool_memory) {
free(mgr);
return NULL;
}
mgr->pool_size = total_size;
mgr->base.name = "Memory Pool Manager";
mgr->base.ops = &pool_ops;
mgr->base.private_data = mgr;
mgr->base.total_size = total_size;
mgr->base.used_size = 0;
mgr->base.peak_used = 0;
/* 初始化等级 */
init_pool_levels(mgr);
return (mem_manager_t*)mgr;
}
/**
* @brief 查找合适的内存池等级
*/
static pool_level_t* find_suitable_level(mem_pool_manager_t *mgr,
uint32_t size) {
for (int i = 0; i < mgr->level_count; i++) {
if (mgr->levels[i].block_size >= size) {
return &mgr->levels[i];
}
}
return NULL;
}
/**
* @brief 池内存分配
*/
static void* pool_alloc(void *mgr_priv, uint32_t size, uint32_t align) {
mem_pool_manager_t *mgr = (mem_pool_manager_t*)mgr_priv;
pool_level_t *level;
pool_block_t *block;
/* 加上对齐开销 */
uint32_t real_size = size + align - 1;
level = find_suitable_level(mgr, real_size);
if (!level || !level->free_list) {
mgr->fail_count++;
return NULL;
}
/* 从空闲链表取下 */
block = level->free_list;
level->free_list = block->next;
level->free_count--;
mgr->alloc_count++;
/* 返回可用数据区 */
return (void*)((uint8_t*)block + sizeof(pool_block_t));
}
/**
* @brief 池内存释放
*/
static void pool_free(void *mgr_priv, void *ptr) {
mem_pool_manager_t *mgr = (mem_pool_manager_t*)mgr_priv;
pool_block_t *block;
pool_level_t *level;
if (!ptr) return;
/* 获取块头部 */
block = (pool_block_t*)((uint8_t*)ptr - sizeof(pool_block_t));
if (block->magic != MEM_MAGIC) {
fprintf(stderr, "Invalid memory block\n");
return;
}
/* 查找所属等级 */
for (int i = 0; i < mgr->level_count; i++) {
level = &mgr->levels[i];
if (block->size == level->block_size) {
/* 放回空闲链表 */
block->next = level->free_list;
level->free_list = block;
level->free_count++;
mgr->free_count++;
return;
}
}
fprintf(stderr, "Block size %u not found in pool\n", block->size);
}
四、大块MMAP内存管理
/**
* @file mem_mmap.h
* @brief MMAP大块内存管理器
* @details 使用mmap管理大块内存,适合视频帧等大数据
*/
#ifndef MEM_MMAP_H
#define MEM_MMAP_H
#include "mem_core.h"
#include <sys/mman.h>
/*==================== MMAP配置 ====================*/
#define MMAP_MIN_SIZE (1024 * 1024) /*!< 最小MMAP大小: 1MB */
#define MMAP_ALIGNMENT 4096 /*!< 页对齐 */
#define MMAP_MAX_BLOCKS 128 /*!< 最大块数 */
/**
* @brief MMAP内存块
*/
typedef struct mmap_block {
void *addr; /*!< 映射地址 */
uint32_t size; /*!< 块大小 */
uint32_t used; /*!< 已用大小 */
int fd; /*!< 文件描述符(匿名映射为-1)*/
uint32_t flags; /*!< 映射标志 */
struct mmap_block *next; /*!< 下一个块 */
struct mmap_block *prev; /*!< 上一个块 */
/* 统计 */
uint32_t alloc_count;
uint32_t free_count;
} mmap_block_t;
/**
* @brief MMAP内存管理器
*/
typedef struct mem_mmap_manager {
mem_manager_t base; /*!< 基类 */
/* 内存块管理 */
mmap_block_t *blocks; /*!< 所有块链表 */
mmap_block_t *free_blocks; /*!< 空闲块链表 */
uint32_t block_count;
/* 缓存池 */
mmap_block_t *block_cache; /*!< 块缓存数组 */
/* 配置 */
uint32_t page_size;
uint32_t min_size;
/* 统计 */
uint64_t total_mapped;
uint64_t total_unmapped;
} mem_mmap_manager_t;
/**
* @brief 创建MMAP内存管理器
* @return 内存管理器指针
*/
mem_manager_t* mem_mmap_create(void);
/**
* @brief 预分配MMAP区域
* @param mgr 管理器
* @param size 预分配大小
* @return 0成功,-1失败
*/
int mem_mmap_prealloc(mem_manager_t *mgr, uint32_t size);
/**
* @brief 销毁MMAP管理器
*/
void mem_mmap_destroy(mem_manager_t *mgr);
#endif /* MEM_MMAP_H */
/**
* @file mem_mmap.c
* @brief MMAP大块内存管理实现
*/
#include "mem_mmap.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
/* 私有操作函数 */
static void* mmap_alloc(void *mgr, uint32_t size, uint32_t align);
static void mmap_free(void *mgr, void *ptr);
static void mmap_dump(void *mgr);
static uint32_t mmap_get_used(void *mgr);
static uint32_t mmap_get_total(void *mgr);
static mem_ops_t mmap_ops = {
.alloc = mmap_alloc,
.free = mmap_free,
.dump = mmap_dump,
.get_used = mmap_get_used,
.get_total = mmap_get_total
};
/**
* @brief 创建MMAP管理器
*/
mem_manager_t* mem_mmap_create(void) {
mem_mmap_manager_t *mgr;
mgr = (mem_mmap_manager_t*)malloc(sizeof(mem_mmap_manager_t));
if (!mgr) return NULL;
memset(mgr, 0, sizeof(mem_mmap_manager_t));
mgr->base.name = "MMAP Memory Manager";
mgr->base.ops = &mmap_ops;
mgr->base.private_data = mgr;
mgr->base.total_size = 0;
mgr->base.used_size = 0;
mgr->page_size = sysconf(_SC_PAGESIZE);
mgr->min_size = MMAP_MIN_SIZE;
/* 初始化块缓存 */
mgr->block_cache = (mmap_block_t*)calloc(MMAP_MAX_BLOCKS,
sizeof(mmap_block_t));
return (mem_manager_t*)mgr;
}
/**
* @brief 创建新的MMAP块
*/
static mmap_block_t* create_mmap_block(mem_mmap_manager_t *mgr,
uint32_t size) {
mmap_block_t *block;
void *addr;
/* 页对齐 */
size = (size + mgr->page_size - 1) & ~(mgr->page_size - 1);
/* 使用匿名映射 */
addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED) {
perror("mmap failed");
return NULL;
}
/* 从缓存获取块结构 */
block = &mgr->block_cache[mgr->block_count];
mgr->block_count++;
block->addr = addr;
block->size = size;
block->used = 0;
block->fd = -1;
block->flags = 0;
block->alloc_count = 0;
block->free_count = 0;
/* 添加到链表 */
block->next = mgr->blocks;
if (mgr->blocks) {
mgr->blocks->prev = block;
}
mgr->blocks = block;
mgr->total_mapped += size;
mgr->base.total_size += size;
printf("MMAP: Created block %p size %u\n", addr, size);
return block;
}
/**
* @brief 查找合适的MMAP块
*/
static mmap_block_t* find_suitable_block(mem_mmap_manager_t *mgr,
uint32_t size) {
mmap_block_t *block = mgr->blocks;
/* 查找有空闲空间的块 */
while (block) {
if (block->size - block->used >= size) {
return block;
}
block = block->next;
}
/* 没有找到,创建新块 */
uint32_t new_size = size > mgr->min_size ? size : mgr->min_size;
return create_mmap_block(mgr, new_size);
}
/**
* @brief MMAP内存分配
*/
static void* mmap_alloc(void *mgr_priv, uint32_t size, uint32_t align) {
mem_mmap_manager_t *mgr = (mem_mmap_manager_t*)mgr_priv;
mmap_block_t *block;
void *ptr;
uint32_t aligned_size;
/* 对齐到页 */
aligned_size = (size + mgr->page_size - 1) & ~(mgr->page_size - 1);
block = find_suitable_block(mgr, aligned_size);
if (!block) return NULL;
/* 在当前块中分配 */
ptr = (void*)((uint8_t*)block->addr + block->used);
block->used += aligned_size;
block->alloc_count++;
mgr->base.used_size += aligned_size;
/* 记录分配信息(在块内存储头部)*/
mem_header_t *header = (mem_header_t*)ptr;
header->magic = MEM_MAGIC;
header->type = MEM_TYPE_MMAP_BLOCK;
header->size = size;
header->block_size = aligned_size;
header->next = NULL;
header->prev = NULL;
header->ref_count = 1;
header->owner = block;
return (void*)((uint8_t*)ptr + MEM_HEADER_SIZE);
}
/**
* @brief MMAP内存释放
*/
static void mmap_free(void *mgr_priv, void *ptr) {
mem_mmap_manager_t *mgr = (mem_mmap_manager_t*)mgr_priv;
mem_header_t *header;
mmap_block_t *block;
if (!ptr) return;
header = (mem_header_t*)((uint8_t*)ptr - MEM_HEADER_SIZE);
if (header->magic != MEM_MAGIC) {
fprintf(stderr, "Invalid memory header\n");
return;
}
block = (mmap_block_t*)header->owner;
if (!block) return;
/* 这里简单处理:不实际释放,只标记 */
block->used -= header->block_size;
block->free_count++;
mgr->base.used_size -= header->block_size;
/* 如果块完全空闲,可以考虑munmap */
if (block->used == 0 && block->size > mgr->min_size * 2) {
/* 可以释放大块空闲内存 */
munmap(block->addr, block->size);
mgr->total_unmapped += block->size;
mgr->base.total_size -= block->size;
/* 从链表中移除 */
if (block->prev) {
block->prev->next = block->next;
} else {
mgr->blocks = block->next;
}
if (block->next) {
block->next->prev = block->prev;
}
}
}
五、视频帧专用内存管理
/**
* @file mem_video.h
* @brief 视频帧专用内存管理器
* @details 针对视频帧特点优化的内存管理
*/
#ifndef MEM_VIDEO_H
#define MEM_VIDEO_H
#include "mem_core.h"
/*==================== 视频帧配置 ====================*/
#define MAX_FRAME_WIDTH 3840 /*!< 最大宽度 4K */
#define MAX_FRAME_HEIGHT 2160 /*!< 最大高度 4K */
#define MAX_FRAME_FORMATS 8 /*!< 最大格式数 */
#define VIDEO_FRAME_POOL_SIZE 16 /*!< 帧池大小 */
/**
* @brief 视频像素格式
*/
typedef enum {
PIX_FMT_NV12, /*!< NV12 YUV420 半平面 */
PIX_FMT_NV21, /*!< NV21 YUV420 半平面 */
PIX_FMT_YUYV, /*!< YUYV 打包格式 */
PIX_FMT_RGB24, /*!< RGB24 */
PIX_FMT_BGR24, /*!< BGR24 */
PIX_FMT_ARGB, /*!< ARGB32 */
PIX_FMT_MJPEG, /*!< MJPEG压缩帧 */
PIX_FMT_H264 /*!< H.264压缩帧 */
} pixel_format_t;
/**
* @brief 视频帧信息
*/
typedef struct video_frame {
mem_header_t header; /*!< 内存头部 */
/* 帧属性 */
uint32_t width; /*!< 宽度 */
uint32_t height; /*!< 高度 */
pixel_format_t format; /*!< 像素格式 */
uint32_t stride; /*!< 行跨度 */
/* 时间信息 */
uint64_t timestamp; /*!< 时间戳 */
uint32_t sequence; /*!< 序列号 */
/* 数据区 */
uint8_t *y_plane; /*!< Y平面 */
uint8_t *uv_plane; /*!< UV平面 */
uint32_t y_size; /*!< Y平面大小 */
uint32_t uv_size; /*!< UV平面大小 */
/* 引用计数 */
uint32_t ref_count; /*!< 引用计数 */
/* 回调 */
void (*release_cb)(struct video_frame *frame, void *userdata);
void *cb_userdata;
} video_frame_t;
/**
* @brief 视频帧池
*/
typedef struct video_frame_pool {
video_frame_t *frames; /*!< 帧数组 */
uint32_t pool_size; /*!< 池大小 */
uint32_t free_count; /*!< 空闲帧数 */
uint32_t *free_list; /*!< 空闲索引链表 */
/* 帧属性模板 */
uint32_t width;
uint32_t height;
pixel_format_t format;
uint32_t frame_size;
/* 内存管理器 */
mem_manager_t *mmap_mgr; /*!< 底层MMAP管理器 */
} video_frame_pool_t;
/**
* @brief 视频内存管理器
*/
typedef struct mem_video_manager {
mem_manager_t base; /*!< 基类 */
/* 多个帧池(不同分辨率/格式)*/
video_frame_pool_t *pools[MAX_FRAME_FORMATS];
uint32_t pool_count;
/* 活跃帧跟踪 */
video_frame_t *active_frames[VIDEO_FRAME_POOL_SIZE * 2];
uint32_t active_count;
/* 底层管理器 */
mem_manager_t *mmap_mgr; /*!< MMAP管理器 */
} mem_video_manager_t;
/**
* @brief 创建视频内存管理器
*/
mem_manager_t* mem_video_create(void);
/**
* @brief 创建视频帧池
* @param mgr 视频管理器
* @param width 帧宽度
* @param height 帧高度
* @param format 像素格式
* @param pool_size 池大小
* @return 0成功,-1失败
*/
int mem_video_create_pool(mem_manager_t *mgr, uint32_t width,
uint32_t height, pixel_format_t format,
uint32_t pool_size);
/**
* @brief 从池中获取视频帧
*/
video_frame_t* mem_video_get_frame(mem_manager_t *mgr,
uint32_t width, uint32_t height,
pixel_format_t format);
/**
* @brief 释放视频帧回池
*/
void mem_video_put_frame(video_frame_t *frame);
#endif /* MEM_VIDEO_H */
/**
* @file mem_video.c
* @brief 视频帧专用内存管理实现
*/
#include "mem_video.h"
#include "mem_mmap.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 私有操作函数 */
static void* video_alloc(void *mgr, uint32_t size, uint32_t align);
static void video_free(void *mgr, void *ptr);
static void video_dump(void *mgr);
static uint32_t video_get_used(void *mgr);
static uint32_t video_get_total(void *mgr);
static mem_ops_t video_ops = {
.alloc = video_alloc,
.free = video_free,
.dump = video_dump,
.get_used = video_get_used,
.get_total = video_get_total
};
/**
* @brief 计算视频帧大小
*/
static uint32_t calculate_frame_size(uint32_t width, uint32_t height,
pixel_format_t format) {
switch (format) {
case PIX_FMT_NV12:
case PIX_FMT_NV21:
return width * height * 3 / 2; /* Y + UV */
case PIX_FMT_YUYV:
return width * height * 2;
case PIX_FMT_RGB24:
case PIX_FMT_BGR24:
return width * height * 3;
case PIX_FMT_ARGB:
return width * height * 4;
default:
return width * height * 3 / 2; /* 默认YUV420 */
}
}
/**
* @brief 创建视频内存管理器
*/
mem_manager_t* mem_video_create(void) {
mem_video_manager_t *mgr;
mgr = (mem_video_manager_t*)calloc(1, sizeof(mem_video_manager_t));
if (!mgr) return NULL;
mgr->base.name = "Video Memory Manager";
mgr->base.ops = &video_ops;
mgr->base.private_data = mgr;
/* 创建底层MMAP管理器 */
mgr->mmap_mgr = mem_mmap_create();
return (mem_manager_t*)mgr;
}
/**
* @brief 创建视频帧池
*/
int mem_video_create_pool(mem_manager_t *base_mgr, uint32_t width,
uint32_t height, pixel_format_t format,
uint32_t pool_size) {
mem_video_manager_t *mgr = (mem_video_manager_t*)base_mgr->private_data;
video_frame_pool_t *pool;
uint32_t frame_size;
uint32_t total_size;
uint8_t *mem;
frame_size = calculate_frame_size(width, height, format);
total_size = frame_size * pool_size;
/* 预分配MMAP内存 */
mem = (uint8_t*)mem_alloc(mgr->mmap_mgr, total_size);
if (!mem) return -1;
pool = (video_frame_pool_t*)calloc(1, sizeof(video_frame_pool_t));
if (!pool) return -1;
pool->frames = (video_frame_t*)calloc(pool_size, sizeof(video_frame_t));
pool->free_list = (uint32_t*)calloc(pool_size, sizeof(uint32_t));
pool->pool_size = pool_size;
pool->free_count = pool_size;
pool->width = width;
pool->height = height;
pool->format = format;
pool->frame_size = frame_size;
pool->mmap_mgr = mgr->mmap_mgr;
/* 初始化帧数组 */
for (uint32_t i = 0; i < pool_size; i++) {
video_frame_t *frame = &pool->frames[i];
uint8_t *frame_mem = mem + i * frame_size;
frame->width = width;
frame->height = height;
frame->format = format;
frame->stride = width;
/* 设置平面指针(NV12格式)*/
if (format == PIX_FMT_NV12 || format == PIX_FMT_NV21) {
frame->y_plane = frame_mem;
frame->uv_plane = frame_mem + width * height;
frame->y_size = width * height;
frame->uv_size = width * height / 2;
} else {
frame->y_plane = frame_mem;
frame->y_size = frame_size;
}
frame->ref_count = 0;
pool->free_list[i] = i;
}
mgr->pools[mgr->pool_count++] = pool;
printf("Created video frame pool: %ux%u, format %d, %u frames, "
"total %u bytes\n", width, height, format, pool_size, total_size);
return 0;
}
/**
* @brief 从池中获取视频帧
*/
video_frame_t* mem_video_get_frame(mem_manager_t *base_mgr,
uint32_t width, uint32_t height,
pixel_format_t format) {
mem_video_manager_t *mgr = (mem_video_manager_t*)base_mgr->private_data;
video_frame_pool_t *pool = NULL;
uint32_t frame_index;
video_frame_t *frame;
/* 查找匹配的帧池 */
for (uint32_t i = 0; i < mgr->pool_count; i++) {
if (mgr->pools[i]->width == width &&
mgr->pools[i]->height == height &&
mgr->pools[i]->format == format) {
pool = mgr->pools[i];
break;
}
}
if (!pool || pool->free_count == 0) {
return NULL;
}
/* 从空闲列表获取索引 */
frame_index = pool->free_list[--pool->free_count];
frame = &pool->frames[frame_index];
/* 初始化帧 */
frame->timestamp = 0;
frame->sequence = 0;
frame->ref_count = 1;
frame->release_cb = NULL;
frame->cb_userdata = NULL;
/* 添加到活跃列表 */
mgr->active_frames[mgr->active_count++] = frame;
return frame;
}
/**
* @brief 释放视频帧回池
*/
void mem_video_put_frame(video_frame_t *frame) {
mem_video_manager_t *mgr; /* 需要从frame获取 */
video_frame_pool_t *pool = NULL;
if (!frame) return;
frame->ref_count--;
if (frame->ref_count > 0) return;
/* 这里需要找到所属的pool,简化处理 */
/* 实际应用中需要从frame反向找到pool */
if (frame->release_cb) {
frame->release_cb(frame, frame->cb_userdata);
}
/* 重置帧 */
memset(frame->y_plane, 0, frame->y_size);
if (frame->uv_plane) {
memset(frame->uv_plane, 0, frame->uv_size);
}
}
/**
* @brief 视频内存分配(通用接口)
*/
static void* video_alloc(void *mgr_priv, uint32_t size, uint32_t align) {
mem_video_manager_t *mgr = (mem_video_manager_t*)mgr_priv;
/* 对于非视频帧的小内存,转发给MMAP管理器 */
return mem_alloc(mgr->mmap_mgr, size);
}
/**
* @brief 视频内存释放
*/
static void video_free(void *mgr_priv, void *ptr) {
mem_video_manager_t *mgr = (mem_video_manager_t*)mgr_priv;
mem_free(mgr->mmap_mgr, ptr);
}
/**
* @brief 打印管理器状态
*/
static void video_dump(void *mgr_priv) {
mem_video_manager_t *mgr = (mem_video_manager_t*)mgr_priv;
printf("\n=== Video Memory Manager Dump ===\n");
printf("Pool count: %u\n", mgr->pool_count);
printf("Active frames: %u\n", mgr->active_count);
for (uint32_t i = 0; i < mgr->pool_count; i++) {
video_frame_pool_t *pool = mgr->pools[i];
printf(" Pool %u: %ux%u format %d, %u/%u free\n",
i, pool->width, pool->height, pool->format,
pool->free_count, pool->pool_size);
}
}
六、测试程序
/**
* @file test_memory.c
* @brief 内存管理测试程序
* @details 测试各种内存管理器的功能
*/
#include "mem_pool.h"
#include "mem_mmap.h"
#include "mem_video.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/**
* @brief 测试小内存池
*/
void test_mem_pool(void) {
printf("\n=== Testing Memory Pool ===\n");
/* 创建256KB内存池 */
mem_manager_t *pool = mem_pool_create(256 * 1024);
if (!pool) {
printf("Failed to create memory pool\n");
return;
}
/* 分配各种大小的内存 */
void *ptr1 = MEM_ALLOC(pool, 32);
void *ptr2 = MEM_ALLOC(pool, 64);
void *ptr3 = MEM_ALLOC(pool, 128);
void *ptr4 = MEM_ALLOC(pool, 256);
printf("Allocated: %p(32), %p(64), %p(128), %p(256)\n",
ptr1, ptr2, ptr3, ptr4);
/* 写入测试数据 */
if (ptr1) strcpy((char*)ptr1, "Memory Pool Test");
if (ptr2) memset(ptr2, 0xAA, 64);
if (ptr3) memset(ptr3, 0xBB, 128);
/* 释放 */
MEM_FREE(pool, ptr1);
MEM_FREE(pool, ptr2);
MEM_FREE(pool, ptr3);
MEM_FREE(pool, ptr4);
pool->ops->dump(pool->private_data);
mem_pool_destroy(pool);
}
/**
* @brief 测试MMAP大块内存
*/
void test_mem_mmap(void) {
printf("\n=== Testing MMAP Memory ===\n");
mem_manager_t *mmap_mgr = mem_mmap_create();
if (!mmap_mgr) {
printf("Failed to create MMAP manager\n");
return;
}
/* 分配大块内存 */
void *buf1 = MEM_ALLOC(mmap_mgr, 2 * 1024 * 1024); /* 2MB */
void *buf2 = MEM_ALLOC(mmap_mgr, 4 * 1024 * 1024); /* 4MB */
void *buf3 = MEM_ALLOC(mmap_mgr, 1 * 1024 * 1024); /* 1MB */
printf("Allocated: %p(2MB), %p(4MB), %p(1MB)\n", buf1, buf2, buf3);
/* 写入数据 */
if (buf1) memset(buf1, 0x11, 2 * 1024 * 1024);
if (buf2) memset(buf2, 0x22, 4 * 1024 * 1024);
/* 释放 */
MEM_FREE(mmap_mgr, buf1);
MEM_FREE(mmap_mgr, buf2);
MEM_FREE(mmap_mgr, buf3);
mmap_mgr->ops->dump(mmap_mgr->private_data);
mem_mmap_destroy(mmap_mgr);
}
/**
* @brief 测试视频帧管理
*/
void test_video_frames(void) {
printf("\n=== Testing Video Frame Management ===\n");
mem_manager_t *video_mgr = mem_video_create();
if (!video_mgr) {
printf("Failed to create video manager\n");
return;
}
/* 创建1080p帧池 */
mem_video_create_pool(video_mgr, 1920, 1080, PIX_FMT_NV12, 4);
/* 创建720p帧池 */
mem_video_create_pool(video_mgr, 1280, 720, PIX_FMT_NV12, 8);
/* 获取视频帧 */
video_frame_t *frame1 = mem_video_get_frame(video_mgr,
1920, 1080, PIX_FMT_NV12);
video_frame_t *frame2 = mem_video_get_frame(video_mgr,
1280, 720, PIX_FMT_NV12);
video_frame_t *frame3 = mem_video_get_frame(video_mgr,
1920, 1080, PIX_FMT_NV12);
if (frame1) {
frame1->timestamp = 1000;
frame1->sequence = 1;
printf("Got frame1: %ux%u, ts=%llu\n",
frame1->width, frame1->height,
(unsigned long long)frame1->timestamp);
}
/* 模拟使用帧 */
sleep(1);
/* 释放帧 */
if (frame1) mem_video_put_frame(frame1);
if (frame2) mem_video_put_frame(frame2);
if (frame3) mem_video_put_frame(frame3);
video_mgr->ops->dump(video_mgr->private_data);
/* 这里需要添加销毁函数 */
/* mem_video_destroy(video_mgr); */
}
/**
* @brief 主函数
*/
int main(void) {
printf("Memory Management System Test\n");
printf("============================\n");
test_mem_pool();
test_mem_mmap();
test_video_frames();
printf("\nAll tests completed.\n");
return 0;
}
七、Makefile
# Makefile for Memory Manager
CC = gcc
CFLAGS = -Wall -Wextra -g -I./include
LDFLAGS = -lpthread
SRCDIR = src
INCDIR = include
TESTDIR = test
SOURCES = $(SRCDIR)/mem_core.c \
$(SRCDIR)/mem_pool.c \
$(SRCDIR)/mem_mmap.c \
$(SRCDIR)/mem_video.c
OBJECTS = $(SOURCES:.c=.o)
TEST_TARGET = test_memory
all: $(TEST_TARGET)
$(TEST_TARGET): $(OBJECTS) $(TESTDIR)/test_memory.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(OBJECTS) $(TEST_TARGET)
run: $(TEST_TARGET)
./$(TEST_TARGET)
.PHONY: all clean run
八、设计思想总结
-
树形结构设计:
-
mem_manager_t作为基类 -
各具体管理器继承基类
-
视频管理器包含多个帧池
-
-
内存管理策略:
-
小内存:内存池预分配,避免碎片
-
大内存:MMAP管理,支持大块连续内存
-
视频帧:专用管理器,支持引用计数
-
-
统一接口:
-
所有管理器实现相同的
mem_ops_t -
支持调试信息(文件、行号)
-
统一的内存头部管理
-
-
视频优化:
-
帧池化,避免频繁分配
-
支持多种像素格式
-
引用计数管理生命周期
-
更多推荐
所有评论(0)