当软件性能优化到一定程度之后,用vturn查看hotspots,将会发现malloc/delete会花费很高比例的时间,此时如果是多线程程序,频繁的lock将会是一个瓶颈,这里有一篇oracle的文章,很好的介绍了这样的情况http://www.oracle.com/technetwork/articles/servers-storage-dev/mem-alloc-1557798.html
在linux平台,此时我们主要考虑到两种优化方案,各自都有很细节的文章可以参考
1. google的MTMalloc (http://goog-perftools.sourceforge.net/doc/tcmalloc.html)
2. gnu的__mt_alloc (http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt12ch32.html)
下面我做了一个简单的测试程序
// test app
void* vectormemorycost(void*){
cout << "malloc test"<< endl;
int blocksize = 512;
for(int j=0;j<20; ++j){
int sum=25000;
char* p1[sum];
for(int i=0; i<sum;++i){
p1[i]=(char*)malloc(blocksize);
}
for(int i=0; i<sum;++i){
free(p1[i]);
}
}
return 0;
}
void* mtallocateMemorycost(void*){
cout << "mt alloc test"<< endl;
typedef pod value_type;
typedef __gnu_cxx::__mt_alloc<value_type> allocator_type;
typedef __gnu_cxx::__pool_base::_Tune tune_type;
///_M_align(__align)
///_M_max_bytes(__maxb)
///_M_min_bin(__minbin),
///_M_chunk_size(__chunk)
///_M_max_threads(__maxthreads),
///_M_freelist_headroom(__headroom)
///_M_force_new(__force)
tune_type t_our(16, 510, 32, 5120, 20, 10, false);
allocator_type a;);
a._M_set_options(t_our);
int blocksize = 512;
for(int j=0;j<20; ++j){
int sum=25000;
allocator_type::pointer p1[sum];
for(int i=0; i<sum;++i){
p1[i]=a.allocate(blocksize);
}
for(int i=0; i<sum;++i){
a.deallocate(p1[i], blocksize);
}
}
return 0;
}
typedef void*(*pFoo)(void*);
void mtallocatePrivate(pFoo func){
int i;
int cores = 4;
pthread_t threads[cores];
/* Create threads to do the work. */
for (i = 0; i < cores; ++i)
// pthread_create (&(threads[i]), NULL, vectormemorycost, NULL);
pthread_create (&(threads[i]), NULL, func, NULL);
/* Wait for all threads to finish. */
for (i = 0; i < cores; ++i)
pthread_join (threads[i], NULL);
}
void mtallocate(){
for(int i=0;i<5;++i){
mtallocatePrivate(mtallocateMemorycost);
mtallocatePrivate(vectormemorycost);
}
}
改变的tune_type参数,发现gnu的最优的情况比malloc快一两倍,最糟糕的情况是反而比malloc慢十倍,很依赖具体的实现情况,另外tcmalloc使用很简单,我们只要改一下link的库,测试的结果是比不用tcmalloc有七八倍的性能提高,从结构上来讲gnu的在更高层次的代码上优化,想通过memory pool和thread id的比较来减少申请内存的次数和不同线程之间的竞争,它最终调用的还是malloc尤其是当申请的内存大于_M_max_bytes的时候就完全是调用malloc了,而TCMalloc是替换掉了系统的malloc,是更加底层的优化。
总结一下,gnu的使用麻烦,接口繁琐,还可能有负面效应,google的比gnu的速度快,使用也方便很多。