天天看點

TCMalloc小記【轉】

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。

<a href="http://blog.csdn.net/chosen0ne/article/details/9338591#t0">一 原理</a>

<a href="http://blog.csdn.net/chosen0ne/article/details/9338591#t1">二 安裝和使用</a>

周末抽空看了一下tcmalloc,了解了個大概。下面記錄一下。

tcmalloc就是一個記憶體配置設定器,管理堆記憶體,主要影響malloc和free,用于降低頻繁配置設定、釋放記憶體造成的性能損耗,并且有效地控制記憶體碎片。glibc中的記憶體配置設定器是ptmalloc2,tcmalloc号稱要比它快。一次malloc和free操作,ptmalloc需要300ns,而tcmalloc隻要50ns。同時tcmalloc也優化了小對象的存儲,需要更少的空間。tcmalloc特别對多線程做了優化,對于小對象的配置設定基本上是不存在鎖競争,而大對象使用了細粒度、高效的自旋鎖(spinlock)。配置設定給線程的本地緩存,在長時間空閑的情況下會被回收,供其他線程使用,這樣提高了在多線程情況下的記憶體使用率,不會浪費記憶體,而這一點ptmalloc2是做不到的。

tcmalloc差別的對待大、小對象。它為每個線程配置設定了一個線程局部的cache,線程需要的小對象都是在其cache中配置設定的,由于是thread local的,是以基本上是無鎖操作(在cache不夠,需要增加記憶體時,會加鎖)。同時,tcmalloc維護了程序級别的cache,所有的大對象都在這個cache中配置設定,由于多個線程的大對象的配置設定都從這個cache進行,是以必須加鎖通路。在實際的程式中,小對象配置設定的頻率要遠遠高于大對象,通過這種方式(小對象無鎖配置設定,大對象加鎖配置設定)可以提升整體性能。

線程級别cache和程序級别cache實際上就是一個多級的空閑塊清單(Free List)。一個Free List以大小為k bytes倍數的空閑塊進行配置設定,包含n個連結清單,每個連結清單存放大小為nk bytes的空閑塊。在tcmalloc中,&lt;=32KB的對象被稱作是小對象,&gt;32KB的是大對象。在小對象中,&lt;=1024bytes的對象以8n bytes配置設定,1025&lt;size&lt;=32KB的對象以128n bytes大小配置設定,比如:要配置設定20bytes則傳回的空閑塊大小是24bytes的,這樣在&lt;=1024的情況下最多浪費7bytes,&gt;1025則浪費127bytes。而大對象是以頁大小4KB進行對齊的,最多會浪費4KB - 1 bytes。下圖就是一個基本的free list的示意圖:

TCMalloc小記【轉】

實際上,一個free list(我稱之為空閑塊清單)就是一個數組索引多個連結清單,每個連結清單存放相同大小的塊。可以根據要配置設定的記憶體大小size算出合适的塊在free list中的下标,然後找到對應的空閑塊連結清單。

TCMalloc小記【轉】

Thread-local free list:線程本地的空閑塊cache,用于配置設定小對象。

Heap free list:中心free list,全局唯一,用于按頁對齊配置設定大對象或者是将連續的多個頁(被稱作span)分割成多個小對象的空閑塊配置設定給thread-local free list。

Page array:用于描述目前tcmalloc持有的記憶體狀态,完成的是從page number到span的映射。

下面看一下小對象的配置設定:

(1)根據配置設定的size計算出對應的空閑塊大小,進而确定對應空閑塊連結清單,然後從thread local的free list進行配置設定。

(2)如果的空閑塊連結清單非空,直接将頭結點對應的空閑塊傳回并從空閑塊連結清單中将其删除。

(3)如果空閑塊連結清單是空的,需要從heap free list擷取一個span。如果heap free list非空,則将span切分成多個相同大小的空閑塊插入空閑塊連結清單中,然後傳回頭結點。

(4)如果heap free list是空的,則調用sbrk或者mmap進行記憶體的配置設定一系列連續的記憶體頁,作為span,然後切分成多個相同大小的空閑塊插入空閑塊連結清單,然後傳回頭結點。

大對象的配置設定就要簡單多了,直接從heap free list配置設定4nKB大小的空閑塊即可,如果heap free list不存在該大小的空閑塊,通過系統調用配置設定連續的記憶體頁。

tcmalloc還會對thread local cache進行垃圾收集,進而避免記憶體浪費。

gcc -DHAVE_CONFIG_H -I. -I../include -I../include -I../include/tdep-x86_64 -I. -D_GNU_SOURCE -DNDEBUG -g -O2 -fexceptions -Wall -Wsign-compare -MT setjmp/longjmp.lo -MD -MP -MF setjmp/.deps/longjmp.Tpo -c setjmp/longjmp.c -fPIC -DPIC -o setjmp/.libs/longjmp.o  

/usr/include/x86_64-linux-gnu/bits/setjmp2.h:26:13: error: 'longjmp' aliased to undefined symbol '_longjmp  

是因為缺少編譯選項U_FORTIFY_SOURCE,解決方法有兩種:

1,尚未調用configure進行配置,則執行CPPFLAGS=-U_FORTIFY_SOURCE ./configure ... 會自動将編譯選項添加到Makefile中。

2,已經配置過,直接修改Makefile,查找CPPFLAGS然後添加上-U_FORTIFY_SOURCE。

然後就是安裝gperftools,這個正常安裝即可,預設安裝到/usr/local/lib下,完成後調用lddconfig添加到動态連結庫緩存,然後就可以使用了。

使用方法,很簡單,在編譯時加上tcmalloc動态連結庫即可

g++ test.cpp -ltcmalloc  

源碼不需任何修改,tcmalloc會自動替換掉glibc預設的malloc和free,簡簡單單的一條指令就可以提升不少性能,very good。

本文轉自張昺華-sky部落格園部落格,原文連結:http://www.cnblogs.com/sky-heaven/p/6844726.html,如需轉載請自行聯系原作者

繼續閱讀