C++ 实现Buffer 动态分配管理代码实现
发布日期:2021-06-29 14:50:54 浏览次数:3 分类:技术文章

本文共 7890 字,大约阅读时间需要 26 分钟。

C++ 实现Buffer 动态分配管理代码实现

应公司需求,花半天时间写了一个内存buffer 动态管理的代码,需兼顾 性能 和 内存(时间和空间)。

实现功能如下:

  1. 初始化时,常驻两块 buff 用于数据传输。(兼顾 性能)
  2. 在数据高峰期时,当已分配的两块 buff 不够用时,能够实现动态的分配新的buff .
  3. 在数据低峰期时,之前分配的多余的 buff 会自动 free 掉,保证应用不会占用太大的内存。(兼顾 内存)

自动 free buff 的方案实现思路如下:

每个数据自带计数 unused_cnt,初始值为10,每过一秒自动减1,
当系统检测到 数值为0 时,说明 该buff 已长时间未使用,则调用 free 函数释放 buff。

如下代码是下午写的完整的 buff 管理代码,为方便后续维护封装为 class 类,测试 ok ,已上代码库使用。

代码如下:

一、 Class Memory_Manager 头文件代码实现

@ /jni/include/receivedata.h#ifndef RECEIVEDATA#define RECEIVEDATA#include 
#include
#include
#include
#include
// signal#include "libmsdp.h"#include "msdp_type.h"#include
#include
// alarm#include
#include
#include "hicarnative.h"/// mem_alloc.cpp ///typedef struct Video_Buffer_t{ uint32_t lengh_buf; uint8_t *pbuf; bool is_ready; bool is_using; int unused_cnt; // 10: using 0: not using};#define BUFFER_NUM_INIT 2#define BUFFER_NUM_MAX 5 // max size is 1.3824M * 5 = 6.912M#define BUFFER_AUTO_CLEAR_TIME 10 // free unnecessary bufeer#define BUFFER_SIZE 1920*720 // 1,382,400class Memory_Manager{ public: Memory_Manager(); ~Memory_Manager(); void clear_buffer(int index); int get_null_buffer(void); int get_ready_buffer(int times); int push_buffer_data(const uint8_t *pPacket, uint32_t nPktSize); void pop_buffer_data(void); void alarm_work(); private: Video_Buffer_t video_buff[BUFFER_NUM_MAX]; int current_buff_num; //void free_buffer_alarm_fn(int sig);};extern Memory_Manager * mem_manager;//call delete mem_manager when not use/// END ///#endif

二、 Class Memory_Manager 代码实现

@ /jni/memory_manager.cpp#include "receivedata.h"void Memory_Manager::alarm_work(){
ALOGI_D("[Memory_Manager::alarm_work] enter "); if( current_buff_num > BUFFER_NUM_INIT) {
for(int i = BUFFER_NUM_INIT; i
0) && (NULL != video_buff[i].pbuf) && (0 == video_buff[i].lengh_buf)) {
video_buff[i].unused_cnt = video_buff[i].unused_cnt -1; ALOGI_D("[free_buffer_alarm_fn] video_buff[%d].unused_cnt = %d ", i, video_buff[i].unused_cnt); } if( (video_buff[i].unused_cnt <= 0) && (NULL != video_buff[i].pbuf) && (0 == video_buff[i].lengh_buf)) {
free(video_buff[i].pbuf); video_buff[i].pbuf = NULL; clear_buffer(i); current_buff_num--; } } } if(current_buff_num != BUFFER_NUM_INIT) alarm(1); }//TODO: add timer function here, check if need release buffervoid free_buffer_alarm_fn(int sig) {
mem_manager->alarm_work(); return; } Memory_Manager::Memory_Manager(){
ALOGI_D("[Memory_Manager::Memory_Manager] enter "); current_buff_num = BUFFER_NUM_INIT; for(int i=0; i < BUFFER_NUM_INIT; i++){
// 0 1 clear_buffer(i); video_buff[i].pbuf = (uint8_t *) malloc(BUFFER_SIZE); } for(int i=BUFFER_NUM_INIT; i < BUFFER_NUM_MAX; i++){
// 2 3 4 clear_buffer(i); } signal(SIGALRM, free_buffer_alarm_fn);} Memory_Manager::~Memory_Manager(){
ALOGI_D("[Memory_Manager::~Memory_Manager] enter "); for(int i=0; i < current_buff_num; i++){
if((NULL != video_buff[i].pbuf)) free(video_buff[i].pbuf); video_buff[i].pbuf = NULL; clear_buffer(i); }}void Memory_Manager::clear_buffer(int index){
ALOGI_D("[Memory_Manager::clear_buffer] start clear video_buff_%d, size=%d +++ ", index , video_buff[index].lengh_buf); video_buff[index].is_ready = false; video_buff[index].is_using = false; video_buff[index].lengh_buf = 0; video_buff[index].unused_cnt = BUFFER_AUTO_CLEAR_TIME;}int Memory_Manager::get_null_buffer(void){
for(int i=0; i < current_buff_num; i++) {
ALOGI_D("[Memory_Manager::get_null_buffer] is_ready=%d, is_using=%d, pbuf not null=%d, lengh_buf=%d, i=%d \n", video_buff[i].is_ready, video_buff[i].is_using, (NULL != video_buff[i].pbuf) ? 1 : 0, video_buff[i].lengh_buf, i ); if( ( false == video_buff[i].is_using) && (0 == video_buff[i].lengh_buf) && ( false == video_buff[i].is_ready) ) {
ALOGI_D("[Memory_Manager::get_null_buffer] return index = %d +++ ", i); return i; } } /// TODO CHECK // Buffer is not enough, alloc a new one if(current_buff_num < BUFFER_NUM_MAX){
current_buff_num++; ALOGI_D("[Memory_Manager::get_null_buffer] Buffer is not enough, alloc a new one, current_buff_num=%d ", current_buff_num); clear_buffer( current_buff_num-1 ); //if( NULL == video_buff[ current_buff_num-1 ].pbuf ){
video_buff[ current_buff_num-1 ].pbuf = (uint8_t *) malloc(BUFFER_SIZE); //}else{
// ALOGI_D("[Memory_Manager::get_null_buffer] malloc error !!! video_buff[%d] is not NULL ", current_buff_num-1); //current_buff_num--; //} video_buff[ current_buff_num-1].unused_cnt = BUFFER_AUTO_CLEAR_TIME; // TODO: start a timer every 1s, Check if need free then alarm(1); return current_buff_num-1; } ALOGI_D("[Memory_Manager::get_null_buffer] current_buff_num=%d reach the max , let data go ", current_buff_num); return -1;}// get a data to uploadint Memory_Manager::get_ready_buffer(int times){
for(int i=0; i < current_buff_num; i++) {
ALOGI_D("[Memory_Manager::get_ready_buffer] is_ready=%d, is_using=%d, pbuf not null=%d, lengh_buf=%d, i=%d \n", video_buff[i].is_ready, video_buff[i].is_using, (NULL != video_buff[i].pbuf) ? 1 : 0, video_buff[i].lengh_buf, i ); if( (true == video_buff[i].is_ready) && (false == video_buff[i].is_using) && (0 != video_buff[i].lengh_buf) ) {
return i; } } if(times == 0) ALOGI_D("[Memory_Manager::get_ready_buffer] has no ready buff !!! "); return -1;}int Memory_Manager::push_buffer_data(const uint8_t *pPacket, uint32_t nPktSize){
int index; index = get_null_buffer(); if(index == -1){
return index; } //video_buff[index].pbuf = (uint8_t *) malloc(nPktSize); // this could be a malloc pool video_buff[index].lengh_buf = nPktSize; memcpy(video_buff[index].pbuf, (uint8_t *)pPacket, nPktSize); video_buff[index].is_ready = true; video_buff[index].is_using = false; ALOGI_D("[Memory_Manager::push_buffer_data] nPktSize = 2 %d", nPktSize); return 0;}void Memory_Manager::pop_buffer_data(void){
int index = get_ready_buffer(0); while( index != -1 ) {
video_buff[index].is_using = true; sendVideoDataNative(video_buff[index].pbuf, video_buff[index].lengh_buf); memset(video_buff[index].pbuf , 0 , BUFFER_SIZE); clear_buffer(index); index = get_ready_buffer(1); }}

三、Class Memory_Manager 使用方法

在实例化 class Memory_Manager 后,使用者不需要操心 buff 的问题,

使用非常简单,
第一步:new 一个 class Memory_Manager 对象。
第二步:调用写数据接口,写数据
第三步:调用读数据接口,上报数据。

当数据量比较大时,buff 内部如何对数据管理分配,完全由 class Memory_Manager 来实现。

@ /jni/libreceivedata.cpp#include "receivedata.h"Memory_Manager * mem_manager;1. 初始化代码    // ciellee 20191010 +++    mem_manager = new Memory_Manager();    // ciellee 20191010 ---2. 将数据写放一块 buff 中    // ciellee 20191010 +++    if( mem_manager->push_buffer_data(pPacket,nPktSize) == 0)    {
pthread_cond_signal(&mDataCondition); } // ciellee 20191010 ---3. 取出数据 // ciellee 20191010 +++ mem_manager->pop_buffer_data(); // ciellee 20191010 ---

转载地址:https://ciellee.blog.csdn.net/article/details/102488219 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:理解 Audio 音频系统三 之 [1] AudioFlinger 启动流程 及 Audio PatchPanel初始化
下一篇:C++ 中重写 ALOG 动态 控制宏控

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月30日 20时54分54秒