redis第一次调用free函数
(gdb) bt
#0 je_free (ptr=0x7ffff661b000) at src/jemalloc.c:1837
#1 0x000000000043194e in zfree (ptr=0x7ffff661b000) at zmalloc.c:204
#2 0x0000000000423ea7 in dictRehash (d=0x7ffff6618060, n=-1) at dict.c:279
#3 0x0000000000423fc6 in _dictRehashStep (d=0x7ffff6618060) at dict.c:318
#4 0x0000000000424077 in dictAddRaw (d=0x7ffff6618060, key=0x7ffff6616081) at dict.c:352
#5 0x0000000000423fef in dictAdd (d=0x7ffff6618060, key=0x7ffff6616081, val=0x917930 ) at dict.c:324
#6 0x00000000004298ab in populateCommandTable () at server.c:2035
#7 0x0000000000428734 in initServerConfig () at server.c:1587
#8 0x000000000042e55a in main (argc=1, argv=0x7fffffffe3f8) at server.c:3984
je_free
tsd_t *tsd = tsd_fetch();得到当前线程的tsd
ifree(tsd, ptr, tcache_get(tsd, false));
tcache = tsd_tcache_get(tsd);
得到tsd的tcache字段
usize = isalloc(ptr, config_prof);
arena_salloc(ptr, demote)
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
(arena_chunk_t *) 0x7ffff6600000
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
(0x7ffff661b000 - 0x7ffff6600000) >> 27
binind = arena_mapbits_binind_get(chunk, pageind);
&chunk->map_bits[pageind-map_bias]
*mapbitsp = 0x61
binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT;
(0x61 & (0xff << 5)) >> 5 = 3,后五位清0,取6-12位
ret = index2size(binind);
64
释放64字节的大小
*tsd_thread_deallocatedp_get(tsd) += usize;
tsd的thread_deallocated += 64
iqalloc(tsd, ptr, tcache);
idalloctm(tsd, ptr, tcache, false);
arena_dalloc(tsd, ptr, tcache);
chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr);
pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE;
mapbits = arena_mapbits_get(chunk, pageind);
0x61
szind_t binind = arena_ptr_small_binind_get(ptr, mapbits);
binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT;
3
先释放到cache中
tcache_dalloc_small(tsd, tcache, ptr, binind);
tbin = &tcache->tbins[binind];
tbin_info = &tcache_bin_info[binind];
tbin->avail[tbin->ncached] = ptr;
tbin->ncached++;
tcache_event(tsd, tcache);
je_arena_dalloc_small,je_arena_dalloc_large在redis启动时没有执行
je_arena_dalloc_small最终调用arena_dalloc_bin_locked_impl
je_arena_dalloc_large最终调用arena_dalloc_large_locked_impl
最终都会调用arena_run_dalloc,在合适的时机,会调用
arena_chunk_dalloc(arena, chunk);
arena_maybe_purge(arena);
下面是手动跟踪代码得到的释放过程
arena_maybe_purge/arena_purge_all
arena_purge
arena_unstash_purged
chunk_dalloc_arena
const chunk_hooks_t chunk_hooks_default.dalloc
chunk_dalloc_default
chunk_dalloc_mmap
pages_unmap
munmap
下面这个堆栈是redis某个timer线程定时会调用的
(gdb) bt
#0 arena_dalloc_bin_locked_impl (arena=0x7ffff7000180, chunk=0x7ffff6600000, ptr=0x7ffff6621568, bitselm=0x7ffff6600108, junked=true)
at src/arena.c:2483
#1 0x0000000000608856 in je_arena_dalloc_bin_junked_locked (arena=0x7ffff7000180, chunk=0x7ffff6600000, ptr=0x7ffff6621568,
bitselm=0x7ffff6600108) at src/arena.c:2511
#2 0x00000000006a4166 in je_tcache_bin_flush_small (tsd=0x7ffff7fd8730, tcache=0x7ffff660d000, tbin=0x7ffff660d060, binind=2, rem=9)
at src/tcache.c:133
#3 0x00000000006a3bc3 in je_tcache_event_hard (tsd=0x7ffff7fd8730, tcache=0x7ffff660d000) at src/tcache.c:44
#4 0x00000000004e7c6e in je_tcache_event (tcache=0x7ffff660d000, tsd=0x7ffff7fd8730) at include/jemalloc/internal/tcache.h:246
#5 je_tcache_alloc_small (zero=false, size=16, tcache=0x7ffff660d000, arena=0x7ffff7000180, tsd=0x7ffff7fd8730)
at include/jemalloc/internal/tcache.h:306
#6 je_arena_malloc (tcache=0x7ffff660d000, zero=false, size=16, arena=0x7ffff7000180, tsd=0x7ffff7fd8730)
at include/jemalloc/internal/arena.h:1173
#7 je_iallocztm (arena=0x0, is_metadata=false, tcache=0x7ffff660d000, zero=false, size=16, tsd=0x7ffff7fd8730)
at include/jemalloc/internal/jemalloc_internal.h:887
#8 je_imalloc (size=16, tsd=0x7ffff7fd8730) at include/jemalloc/internal/jemalloc_internal.h:906
#9 imalloc_body (usize=0x7fffffffc7f8, tsd=0x7fffffffc7f0, size=16) at src/jemalloc.c:1412
#10 je_malloc (size=16) at src/jemalloc.c:1427
#11 0x00000000004316b3 in zmalloc (size=16) at zmalloc.c:125
#12 0x000000000043e37f in createObject (type=0, ptr=0x2354) at object.c:40
#13 0x000000000042804b in createSharedObjects () at server.c:1434
#14 0x000000000042916e in initServer () at server.c:1889
#15 0x000000000042ea65 in main (argc=1, argv=0x7fffffffe3f8) at server.c:4079
搞清楚细节,需要好好扒扒代码了