ITADN

tcmalloc is hoarding memory

#294Openjengelh 创建于 2026-03-18
J
jengelhcommented
Version: tcmalloc 2.17.2 linux-amd64 [openSUSE Tumbleweed 20260316] A program that makes a lot (millions) of small allocations and then frees them makes jemalloc retain all those small buckets for itself rather than returning them to the OS. This issue was originally reported as https://sourceware.org/bugzilla/show_bug.cgi?id=33886 for glibc and https://github.com/jemalloc/jemalloc/issues/2867 for jemalloc, but tcmalloc is just affected the same. **Input code:** ```c #include <stdlib.h> #include <malloc.h> size_t allocsize = 120; void *one_thread(void *) { static const unsigned int nelem = 50000000; char **arr = malloc(sizeof(char *) * nelem); for (size_t i = 0; i < nelem; ++i) arr[i] = malloc(allocsize); for (size_t i = 0; i < nelem; ++i) free(arr[i]); free(arr); return 0; } int main(int argc, char **argv) { allocsize = argc >= 2 ? strtoul(argv[1],nullptr,0) : 120; system("ps u"); one_thread(0); malloc_stats(); // about 6 GB retained system("ps u"); return 0; } ``` **Observed:** ``` 10:08 a4:~/work/gromox $ LD_PRELOAD=/usr/lib64/libtcmalloc.so.4 ./a.out USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND ej 20916 0.0 0.0 17756 11756 pts/3 S+ 10:14 0:00 ./a.out ------------------------------------------------ MALLOC: 90112 ( 0.1 MiB) Bytes in use by application MALLOC: + 6204882944 ( 5917.4 MiB) Bytes in page heap freelist MALLOC: + 38912 ( 0.0 MiB) Bytes in central cache freelist MALLOC: + 262144 ( 0.2 MiB) Bytes in transfer cache freelist MALLOC: + 2048 ( 0.0 MiB) Bytes in thread cache freelists MALLOC: + 47972416 ( 45.8 MiB) Bytes in malloc metadata MALLOC: ------------ MALLOC: = 6253248576 ( 5963.6 MiB) Actual memory used (physical + swap) MALLOC: + 595238912 ( 567.7 MiB) Bytes released to OS (aka unmapped) MALLOC: ------------ MALLOC: = 6848487488 ( 6531.2 MiB) Virtual address space used MALLOC: MALLOC: 56 Spans in use MALLOC: 1 Thread heaps in use MALLOC: 8192 Tcmalloc page size ------------------------------------------------ Call ReleaseFreeMemory() to release freelist memory to the OS (via madvise()). Bytes released to the OS take up virtual address space but no physical memory. USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND ej 20916 98.8 4.6 6707012 6117956 pts/3 S+ 10:14 0:02 ./a.out ``` **Expected to see instead:** Since my million blocks account for almost all allocations the program ever makes, I would expect fragmentation after free() to be low and the 6 MB number reported by ps to significantly go down. ``` first ps: ej 20916 x% x% 17756 11756 pts/3 S+ 10:14 0:00 ./a.out second ps: ej 20911 x% x% 20000 15000 pts/3 S+ 10:08 0:01 ./a.out ```
0 条评论