Inside Ptmalloc2: Peng Xu
Inside Ptmalloc2: Peng Xu
Peng Xu
[email protected]
kernel space
0 7 15 23 31
top chunk
used
1 #include <stdlib.h>
2 int main(void) {
malloc
chunk
3 char* ptr = (char*)malloc(1); heap
4 free(ptr);
5
return 0;
6 } malloc state
heap info
strace output
struct malloc_state {
mutex_t mutex;
int flags;
mfastbinptr fastbinsY[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
unsigned int binmap[BINMAPSIZE];
struct malloc_state *next;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
Question
why are there prev in the data structure?
data structure of malloc chunk
struct malloc_chunk {
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
next chunk
prev size
If the previous chunk is freed, the value of prev size field states the previous chunk size in byte.
Otherwise, the value in previous field is just one part of user data in the previous chunk.
chunk structure of freed one
0 7 15 23 31
prev size if freed
size A M P
meta
forward pointer
data
backward pointer
free space
TLB and Cache
Organization of the freed chunk
The freed chunk will be cached. The pointer will be saved in suitable bins.
There are three types of bins.
I fast bin < 64 bytes
I small bin < 512 bytes
I large bin > 512 bytes
Small bin and large bin are also called normal bins.
singly
fast
linked
bins
list
circular
normal double
bins linked
list
Fastbins
Fastbin is a singly linked list.
1 2 3 4 5 6 7
16 24 32 40 48 56 64
16 24 32 40 48 56 64
16 24 32 40 48 56 64
16 24 32 40 48 56 64
16 24 32 40 48 56 64
16 24 32 40 48 56 64
.. .. .. .. .. .. ..
. . . . . . .
16 24 32 40 48 56 64
Summary of heap layout
top chunk
dirty part
management data
Part II
Algorithm
algorithm for malloc
Version is glibc-2.18
basic steps for malloc
1. fetch an arena
I one area is free
I create a new one if non-area is in idle
2. allocate requested size in the fetched area
I return the requested memory
I return NULL if non-memory available
malloc function
__libc_malloc(size_t bytes)
{
mstate ar_ptr;
void *victim;
void *(*hook) (size_t, const void *)
= force_reg (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
return (*hook)(bytes, RETURN_ADDRESS (0));
arena_lookup(ar_ptr);
arena_lock(ar_ptr, bytes);
if(!ar_ptr)
return 0;
victim = _int_malloc(ar_ptr, bytes);
if(!victim) {
ar_ptr = arena_get_retry(ar_ptr, bytes);
if (__builtin_expect(ar_ptr != NULL, 1)) {
victim = _int_malloc(ar_ptr, bytes);
(void)mutex_unlock(&ar_ptr->mutex);
}
} else
(void)mutex_unlock(&ar_ptr->mutex);
assert(!victim || chunk_is_mmapped(mem2chunk(victim)) ||
ar_ptr == arena_for_chunk(mem2chunk(victim)));
return victim;
}
malloc procedure in one specific area
I fetch freed chunk in the matched bins if the request size falls
into the fastbins or smallbins
I largebin
I do malloc consolidate, consolidated memory is put into
unsorted bins
I do alloation
I if both of above steps failed, try to apply a new memory block
from system
malloc flow chart
algorithm for free memory
I libc malloc
I int malloc
I int free
I malloc consolidate
I sysmalloc
Part III
1. purify
2. valgrind
3. tcmalloc