昨天晚上,我徒弟跑過來講,他的程序的內存占用居高不下,願意是std::map的clear()沒有效果。於是我讓他用erase(begin,end); 試試也不行。
代碼如下:

void release_map(void) { map<int,string> testmap; for(int i=0; i<1000000; i++) { testmap.insert(make_pair(i,"abc")); } testmap.clear(); } int main() { release_map(); while(1) { sleep(1); } return 0; }
用命令 top -p `ps -ef | grep abc | grep -v grep | awk {'print $2'}`, 一查看,占了104M物理內存。
開始我猜測是stl用了自己的緩沖池,clear()並沒有歸還給系統。於是我用了boost::unordered_map試試,一查看,占了78M物理內存(看來hashmap比紅黑樹既快又省空間)。
於是上網查詢資料,stl有很多種allocator,默認采用是的new_allocator,並沒有使用內存緩沖池,針對不同的應用場合,STL中實現了不同的Allocator。
__gnu_cxx::new_allocator<T> Simply wraps ::operator new and ::operator delete.
__gnu_cxx::malloc_allocator<T> Simply wraps malloc and free. There is also a hook for an out-of-memory handler
__gnu_cxx::debug_allocator<T> A wrapper around an arbitrary allocator A. It passes on slightly increased size requests to A, and uses the extra memory to store size information.
__gnu_cxx::__pool_alloc<bool, int> A high-performance, single pool allocator. The reusable memory is shared among identical instantiations of this type.
__gnu_cxx::__mt_alloc<T> A high-performance fixed-size allocatorthat was initially developed specifically to suit the needs of multi threaded applications
__gnu_cxx::bitmap_allocato A high-performance allocator that uses a bit-map to keep track of the used and unused memory locations
發現stl提供的malloc.h有監控功能,於是修改為下面代碼:

#include <iostream> #include <string> #include <map> #include <boost/unordered_map.hpp> #include <malloc.h> using namespace std; using namespace boost; void release_map(void) { malloc_stats(); map<int,string> testmap; sleep(2); for(int i=0; i<1000000; i++) { testmap.insert(make_pair(i,"abc")); } malloc_stats(); testmap.clear(); malloc_stats(); } int main() { release_map(); getchar(); return 0; }
發現clear() 其實已經歸還內存了,內存的持有是 system bytes 。顯然,malloc並沒有把這些內存歸還給系統,而是緩存起來了。所以說,這個例子的罪魁禍首並不是STL,而是glibc的malloc。好吧,既然找到問題,那就要解決它,雖然glibc的緩存也是一番好意,但是由於實際運行環境不能等到什么用戶heap空間內連續空閑內存數據超出一個閾值時才將這片內存歸還給內核。
glibc管理內存目前采用的是ptmalloc2,我測試了google的tcmalloc和Jason Evans的jemalloc。
測試很簡單,把包downlaod下來並解壓,./configure && make && make install即可。
export $LD_PRELOAD="/usr/local/lib/libtcmalloc.so” 或者 export $LD_PRELOAD="/usr/local/lib/libjemalloc.so” (這個要根據自己的實際情況選擇路徑)
然后編譯后可以用ldd查看程序的依賴庫。
測試結果:tcmalloc也不歸還給系統,而jemalloc的clear后不再占用物理內存。
徒弟問了一句jemalloc靠譜么,我想想淘寶的Tengine,facebook的folly,redis,firefox,freebsd都是用這個,應該是很靠譜的。你上線去測試看看。
附上一張內存分配性能比較圖片:
參考文獻:
http://blog.163.com/dengminwen@126/blog/static/870226720097189486788/
http://bbs.chinaunix.net/thread-2195511-1-1.html
http://wangkaisino.blog.163.com/blog/static/1870444202011431112323846/