tcmalloc is hoarding memory
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 条评论