最近在使用std::queue的时候,遇到一些奇怪的问题。我们使用std::queue来存放一些临时的缓冲数据,然后有一个线程不断地从queue里取数据,写入到文件中,之后会调用pop()函数将数据弹出。但是很奇怪的地在弹出的过程中,程序的内存占用丝毫没有减少。查了一些资料后发现,貌似std::queue底层自己有一套内存管理机制,只有在程序退出或是queue被销毁的时候才会释放这一部分内存。笔者使用的测试代码如下:
#include <stdio.h>
#include <queue>
#include <WinSock2.h>
template<typename Data>
class concurrent_queue
{
private:
std::queue<Data> the_queue;
public:
void push( const Data& data )
{
the_queue.push( data );
}
bool empty( ) const
{
return the_queue.empty( );
}
Data& front( )
{
return the_queue.front( );
}
Data const& front( ) const
{
return the_queue.front( );
}
void pop( )
{
the_queue.pop( );
}
int size( )
{
return the_queue.size( );
}
};
typedef struct FRAME
{
unsigned char* sPbuf;
int iSize;
};
int main() {
concurrent_queue<FRAME> frame_list;
FRAME f;
// push
for (int i = 0; i < 100000; i ++ ) {
FRAME f;
f.sPbuf = NULL;
f.sPbuf = new byte[ 1000 ];
f.iSize = 1000;
frame_list.push( f );
}
// pop
for (int i = 0; i < 100000; i ++ ) {
FRAME f2 = frame_list.front( );
delete [] f2.sPbuf;
f2.sPbuf = NULL;
frame_list.pop( );
Sleep(10);
printf("%d\n",i);
}
return 0;
}
在VS2010中编译并运行上面的代码时,发现随着pop()的调用,内存占用并没有减少。解决方法有以下几种:
l 使用list来替代queue,经测试是可行的,在pop的时候内存会减少。但是list的效率要远不如queue了。
l 考虑使用别的编译器,例如gcc,内存也会正常地减少。
l 自己写一个Queue。
贴出一个可以正常减少内存的自定义的Queue代码:
template<typename Data>
class concurrent_queue
{
private:
int _size;
struct queue_block
{
Data q[ 0x40 ];
unsigned short head, tail;
queue_block *next;
queue_block( ) { head = tail = 0; next = NULL; }
};
queue_block *head, *tail;
mutable boost::mutex the_mutex;
public:
concurrent_queue( ) { head = tail = NULL; }
~concurrent_queue( )
{
while ( head )
{
queue_block *p = head;
head = head->next;
delete p;
}
}
void push( const Data& data )
{
boost::mutex::scoped_lock lock( the_mutex );
if ( !head )
head = tail = new queue_block;
if ( ( ( tail->tail + 1 ) & 0x3f ) == tail->head )
{
tail->next = new queue_block;
tail = tail->next;
}
tail->q[ tail->tail ] = data;
tail->tail = ( tail->tail + 1 ) & 0x3f;
_size ++;
}
bool empty( ) const
{
boost::mutex::scoped_lock lock( the_mutex );
return head == NULL;
}
Data& front( )
{
boost::mutex::scoped_lock lock( the_mutex );
return head->q[ head->head ];
}
Data const& front( ) const
{
boost::mutex::scoped_lock lock( the_mutex );
return head->q[ head->head ];
}
void pop( )
{
boost::mutex::scoped_lock lock( the_mutex );
head->head = ( head->head + 1 ) & 0x3f;
if ( head->head == head->tail )
{
queue_block *p = head;
head = head->next;
delete p;
}
_size --;
}
int size( )
{
boost::mutex::scoped_lock lock( the_mutex );
return _size;
}
};