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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <signal.h>    //     signal
#include "libmsdp.h"
#include "msdp_type.h"
#include <cutils/log.h>
#include <unistd.h>    //    alarm
#include <pthread.h>
#include <dlfcn.h> 
#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,400


class 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<BUFFER_NUM_MAX; i++)
        {
            if(    (video_buff[i].unused_cnt > 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 buffer
void 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 upload
int 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 ---	

发布了329 篇原创文章 · 获赞 66 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Ciellee/article/details/102488219