最近在rtp协议实现上碰到个小问题,就是接收数据后用于缓存的jtterbuffer动态分配的问题。原本的实现是静态分配的,预先分配一比较大的内存块,一年多的使用下来一直没有问题。但在最近增加了voip数据优先的flow control之后,视频数据的抖动变得厉害起来,原先的jitterbuffer经常会有满的现象,满了后就会造成丢帧,而视频数据只要一丢帧就必须丢掉接下的所有P帧,所以显示效果上变得不如以前好。但完全加大jitterbuffer又会变成另一种现象:延时会加大。
通过trace发现,jitterbuffer满的情况也较少出现,所以我就想到了用动态分配内存的方法,但是rtp数据接收非常频繁,我又不能不停new和delete,那怎么办呢? 联系到内存池的实现方法,我将实现稍稍改动了下,就比较完美满足了我的需求。
显示定义一个vector
std::vector<_block_t*> m_buffers; // _block_t是一个数据结构,就是固定大小的内存块
接下来是molloc和free函数
// _mem_packet_t是需要使用内存的结构
_boolean_t memutil::mem_alloc( _mem_packet_t *pk, _uint32_t size )
{
threadpool::util::auto_lock_t lock(m_lock_buffers);
if(pk==NULL||size<=0)
return false;
//blk_cnt是需要分配的内存块数量
_uint32_t blk_cnt = (size % ACT_BLOCK_SIZE)==0? (size/ACT_BLOCK_SIZE): ((size/ACT_BLOCK_SIZE) + 1);
//当前已分配数量
_uint32_t allocated_cnt = 0;
unsigned long max_blk_count = m_buffers.size();
//如果当前已经存在空余的内存块,则将指针传递给使用者,并标志为已分配
for(register unsigned i=0; i<max_blk_count && allocated_cnt < blk_cnt; i++)
{
if(m_buffers[i]->m_flag == 0)
{
pk->m_block_list.push(m_buffers[i]);
m_buffers[i]->m_flag = 1;
m_buffers[i]->m_data_size = 0;
allocated_cnt ++;
m_block_used ++;
}
}
//已经分配了足够的内存块,则返回true
if (allocated_cnt == blk_cnt)
{
return true;
}
else
{
//未分配足够的内存块,说明m_buffers中已经没有足够内存块攻使用,则new一个新的内存块,加入到m_buffers列表末尾,然后将指针传递给使用者。
for (int j=0; allocated_cnt<blk_cnt; j++)
{
_mem_block_t* blocktemp = new _mem_block_t;
memset(blocktemp, 0x00, sizeof(_mem_block_t));
m_buffers.push_back(blocktemp);
pk->m_block_list.push(blocktemp);
blocktemp->m_flag = 1;
blocktemp->m_data_size = 0;
allocated_cnt ++ ;
m_block_used ++ ;
}
}
return true;
}
_boolean_t memutil::mem_free( _mem_packet_t *pk )
{
threadpool::util::auto_lock_t lock(m_lock_buffers);
if(pk==NULL)
return false;
// 释放的过程同内存池实现基本相同,只是将内存块标记为未使用,使用者将其指针释放。
for(;;)
{
_mem_block_t * blk = pk->m_block_list.pop();
if(blk == 0)
break;
if(blk->m_flag == 1){
blk->m_flag = 0;
blk->m_data_size = 0;
m_block_used --;
}
}
return true;
}
而真正的内存释放在memutil的析构函数中,这样每个内存块的new和delete都只用使用一次,大大提高了速度。