1 TCMalloc : Thread-Caching Malloc
4 Sanjay Ghemawat, Paul Menage <opensource@google.com>
8 TCMalloc is faster than the glibc 2.3 malloc (available as a separate library
9 called ptmalloc2) and other mallocs that I have tested. ptmalloc2 takes
10 approximately 300 nanoseconds to execute a malloc/free pair on a 2.8 GHz P4
11 (for small objects). The TCMalloc implementation takes approximately 50
12 nanoseconds for the same operation pair. Speed is important for a malloc
13 implementation because if malloc is not fast enough, application writers are
14 inclined to write their own custom free lists on top of malloc. This can lead
15 to extra complexity, and more memory usage unless the application writer is
16 very careful to appropriately size the free lists and scavenge idle objects out
19 TCMalloc also reduces lock contention for multi-threaded programs. For small
20 objects, there is virtually zero contention. For large objects, TCMalloc tries
21 to use fine grained and efficient spinlocks. ptmalloc2 also reduces lock
22 contention by using per-thread arenas but there is a big problem with
23 ptmalloc2's use of per-thread arenas. In ptmalloc2 memory can never move from
24 one arena to another. This can lead to huge amounts of wasted space. For
25 example, in one Google application, the first phase would allocate
26 approximately 300MB of memory for its data structures. When the first phase
27 finished, a second phase would be started in the same address space. If this
28 second phase was assigned a different arena than the one used by the first
29 phase, this phase would not reuse any of the memory left after the first phase
30 and would add another 300MB to the address space. Similar memory blowup
31 problems were also noticed in other applications.
33 Another benefit of TCMalloc is space-efficient representation of small objects.
34 For example, N 8-byte objects can be allocated while using space approximately
35 8N * 1.01 bytes. I.e., a one-percent space overhead. ptmalloc2 uses a four-byte
36 header for each object and (I think) rounds up the size to a multiple of 8
37 bytes and ends up using 16N bytes.
41 To use TCmalloc, just link tcmalloc into your application via the "-ltcmalloc"
44 You can use tcmalloc in applications you didn't compile yourself, by using
47 $ LD_PRELOAD="/usr/lib/libtcmalloc.so"
49 LD_PRELOAD is tricky, and we don't necessarily recommend this mode of usage.
51 TCMalloc includes a heap checker and heap profiler as well.
53 If you'd rather link in a version of TCMalloc that does not include the heap
54 profiler and checker (perhaps to reduce binary size for a static binary), you
55 can link in libtcmalloc_minimal instead.
59 TCMalloc assigns each thread a thread-local cache. Small allocations are
60 satisfied from the thread-local cache. Objects are moved from central data
61 structures into a thread-local cache as needed, and periodic garbage
62 collections are used to migrate memory back from a thread-local cache into the
63 central data structures.
66 TCMalloc treates objects with size <= 32K ("small" objects) differently from
67 larger objects. Large objects are allocated directly from the central heap
68 using a page-level allocator (a page is a 4K aligned region of memory). I.e., a
69 large object is always page-aligned and occupies an integral number of pages.
71 A run of pages can be carved up into a sequence of small objects, each equally
72 sized. For example a run of one page (4K) can be carved up into 32 objects of
75 Small Object Allocation
77 Each small object size maps to one of approximately 170 allocatable
78 size-classes. For example, all allocations in the range 961 to 1024 bytes are
79 rounded up to 1024. The size-classes are spaced so that small sizes are
80 separated by 8 bytes, larger sizes by 16 bytes, even larger sizes by 32 bytes,
81 and so forth. The maximal spacing (for sizes >= ~2K) is 256 bytes.
83 A thread cache contains a singly linked list of free objects per size-class.
85 When allocating a small object: (1) We map its size to the corresponding
86 size-class. (2) Look in the corresponding free list in the thread cache for the
87 current thread. (3) If the free list is not empty, we remove the first object
88 from the list and return it. When following this fast path, TCMalloc acquires
89 no locks at all. This helps speed-up allocation significantly because a lock/
90 unlock pair takes approximately 100 nanoseconds on a 2.8 GHz Xeon.
92 If the free list is empty: (1) We fetch a bunch of objects from a central free
93 list for this size-class (the central free list is shared by all threads). (2)
94 Place them in the thread-local free list. (3) Return one of the newly fetched
95 objects to the applications.
97 If the central free list is also empty: (1) We allocate a run of pages from the
98 central page allocator. (2) Split the run into a set of objects of this
99 size-class. (3) Place the new objects on the central free list. (4) As before,
100 move some of these objects to the thread-local free list.
102 Large Object Allocation
104 A large object size (> 32K) is rounded up to a page size (4K) and is handled by
105 a central page heap. The central page heap is again an array of free lists. For
106 i < 256, the kth entry is a free list of runs that consist of k pages. The
107 256th entry is a free list of runs that have length >= 256 pages:
110 An allocation for k pages is satisfied by looking in the kth free list. If that
111 free list is empty, we look in the next free list, and so forth. Eventually, we
112 look in the last free list if necessary. If that fails, we fetch memory from
113 the system (using sbrk, mmap, or by mapping in portions of /dev/mem).
115 If an allocation for k pages is satisfied by a run of pages of length > k, the
116 remainder of the run is re-inserted back into the appropriate free list in the
121 The heap managed by TCMalloc consists of a set of pages. A run of contiguous
122 pages is represented by a Span object. A span can either be allocated, or free.
123 If free, the span is one of the entries in a page heap linked-list. If
124 allocated, it is either a large object that has been handed off to the
125 application, or a run of pages that have been split up into a sequence of small
126 objects. If split into small objects, the size-class of the objects is recorded
129 A central array indexed by page number can be used to find the span to which a
130 page belongs. For example, span a below occupies 2 pages, span b occupies 1
131 page, span c occupies 5 pages and span d occupies 3 pages.
133 A 32-bit address space can fit 2^20 4K pages, so this central array takes 4MB
134 of space, which seems acceptable. On 64-bit machines, we use a 3-level radix
135 tree instead of an array to map from a page number to the corresponding span
140 When an object is deallocated, we compute its page number and look it up in the
141 central array to find the corresponding span object. The span tells us whether
142 or not the object is small, and its size-class if it is small. If the object is
143 small, we insert it into the appropriate free list in the current thread's
144 thread cache. If the thread cache now exceeds a predetermined size (2MB by
145 default), we run a garbage collector that moves unused objects from the thread
146 cache into central free lists.
148 If the object is large, the span tells us the range of pages covered by the
149 object. Suppose this range is [p,q]. We also lookup the spans for pages p-1 and
150 q+1. If either of these neighboring spans are free, we coalesce them with the
151 [p,q] span. The resulting span is inserted into the appropriate free list in
154 Central Free Lists for Small Objects
156 As mentioned before, we keep a central free list for each size-class. Each
157 central free list is organized as a two-level data structure: a set of spans,
158 and a linked list of free objects per span.
160 An object is allocated from a central free list by removing the first entry
161 from the linked list of some span. (If all spans have empty linked lists, a
162 suitably sized span is first allocated from the central page heap.)
164 An object is returned to a central free list by adding it to the linked list of
165 its containing span. If the linked list length now equals the total number of
166 small objects in the span, this span is now completely free and is returned to
169 Garbage Collection of Thread Caches
171 A thread cache is garbage collected when the combined size of all objects in
172 the cache exceeds 2MB. The garbage collection threshold is automatically
173 decreased as the number of threads increases so that we don't waste an
174 inordinate amount of memory in a program with lots of threads.
176 We walk over all free lists in the cache and move some number of objects from
177 the free list to the corresponding central list.
179 The number of objects to be moved from a free list is determined using a
180 per-list low-water-mark L. L records the minimum length of the list since the
181 last garbage collection. Note that we could have shortened the list by L
182 objects at the last garbage collection without requiring any extra accesses to
183 the central list. We use this past history as a predictor of future accesses
184 and move L/2 objects from the thread cache free list to the corresponding
185 central free list. This algorithm has the nice property that if a thread stops
186 using a particular size, all objects of that size will quickly move from the
187 thread cache to the central free list where they can be used by other threads.
193 The PTMalloc2 package (now part of glibc) contains a unittest program
194 t-test1.c. This forks a number of threads and performs a series of allocations
195 and deallocations in each thread; the threads do not communicate other than by
196 synchronization in the memory allocator.
198 t-test1 (included in google-perftools/tests/tcmalloc, and compiled as
199 ptmalloc_unittest1) was run with a varying numbers of threads (1-20) and
200 maximum allocation sizes (64 bytes - 32Kbytes). These tests were run on a
201 2.4GHz dual Xeon system with hyper-threading enabled, using Linux glibc-2.3.2
202 from RedHat 9, with one million operations per thread in each test. In each
203 case, the test was run once normally, and once with LD_PRELOAD=libtcmalloc.so.
205 The graphs below show the performance of TCMalloc vs PTMalloc2 for several
206 different metrics. Firstly, total operations (millions) per elapsed second vs
207 max allocation size, for varying numbers of threads. The raw data used to
208 generate these graphs (the output of the "time" utility) is available in
211 [tcmalloc-o] [tcmalloc-o] [tcmalloc-o]
212 [tcmalloc-o] [tcmalloc-o] [tcmalloc-o]
213 [tcmalloc-o] [tcmalloc-o] [tcmalloc-o]
215 • TCMalloc is much more consistently scalable than PTMalloc2 - for all thread
216 counts >1 it achieves ~7-9 million ops/sec for small allocations, falling
217 to ~2 million ops/sec for larger allocations. The single-thread case is an
218 obvious outlier, since it is only able to keep a single processor busy and
219 hence can achieve fewer ops/sec. PTMalloc2 has a much higher variance on
220 operations/sec - peaking somewhere around 4 million ops/sec for small
221 allocations and falling to <1 million ops/sec for larger allocations.
222 • TCMalloc is faster than PTMalloc2 in the vast majority of cases, and
223 particularly for small allocations. Contention between threads is less of a
225 • TCMalloc's performance drops off as the allocation size increases. This is
226 because the per-thread cache is garbage-collected when it hits a threshold
227 (defaulting to 2MB). With larger allocation sizes, fewer objects can be
228 stored in the cache before it is garbage-collected.
229 • There is a noticeably drop in the TCMalloc performance at ~32K maximum
230 allocation size; at larger sizes performance drops less quickly. This is
231 due to the 32K maximum size of objects in the per-thread caches; for
232 objects larger than this tcmalloc allocates from the central page heap.
234 Next, operations (millions) per second of CPU time vs number of threads, for
235 max allocation size 64 bytes - 128 Kbytes.
237 [tcmalloc-o] [tcmalloc-o] [tcmalloc-o]
238 [tcmalloc-o] [tcmalloc-o] [tcmalloc-o]
239 [tcmalloc-o] [tcmalloc-o] [tcmalloc-o]
241 Here we see again that TCMalloc is both more consistent and more efficient than
242 PTMalloc2. For max allocation sizes <32K, TCMalloc typically achieves ~2-2.5
243 million ops per second of CPU time with a large number of threads, whereas
244 PTMalloc achieves generally 0.5-1 million ops per second of CPU time, with a
245 lot of cases achieving much less than this figure. Above 32K max allocation
246 size, TCMalloc drops to 1-1.5 million ops per second of CPU time, and PTMalloc
247 drops almost to zero for large numbers of threads (i.e. with PTMalloc, lots of
248 CPU time is being burned spinning waiting for locks in the heavily
249 multi-threaded case).
253 For some systems, TCMalloc may not work correctly on with applications that
254 aren't linked against libpthread.so (or the equivalent on your OS). It should
255 work on Linux using glibc 2.3, but other OS/libc combinations have not been
258 TCMalloc may be somewhat more memory hungry than other mallocs, though it tends
259 not to have the huge blowups that can happen with other mallocs. In particular,
260 at startup TCMalloc allocates approximately 6 MB of memory. It would be easy to
261 roll a specialized version that trades a little bit of speed for more space
264 TCMalloc currently does not return any memory to the system.
266 Don't try to load TCMalloc into a running binary (e.g., using JNI in Java
267 programs). The binary will have allocated some objects using the system malloc,
268 and may try to pass them to TCMalloc for deallocation. TCMalloc will not be
269 able to handle such objects.