了解 TCMalloc 的“释放到操作系统的字节数又名未映射”统计信息

问题描述

我有一个进程在启动时消耗大量内存,但在进程启动后释放了大部分内存。我在之后打印的 tcmalloc 统计数据中看到以下内容

#012MALLOC:       16635888 (   15.9 MiB) Bytes in use by application
#012MALLOC: +            0 (    0.0 MiB) Bytes in page heap freelist
#012MALLOC: +     20007352 (   19.1 MiB) Bytes in central cache freelist
#012MALLOC: +     26367680 (   25.1 MiB) Bytes in transfer cache freelist
#012MALLOC: +      7030680 (    6.7 MiB) Bytes in thread cache freelists
#012MALLOC: +      1978560 (    1.9 MiB) Bytes in malloc Metadata
#012MALLOC: =     72020160 (   68.7 MiB) Actual memory used (physical + swap)
#012MALLOC: +    239607808 (  228.5 MiB) Bytes released to OS (aka unmapped). ***
#012MALLOC: =    311627968 (  297.2 MiB) Virtual address space used

在这里我们看到有大约 228 MB 的“释放到操作系统”,但它也表明这仍然是进程虚拟地址空间的一部分。在看到此日志记录后,使用 ps aux 看到的 VSZ 统计数据仍然很高,这一事实证实了这一点。

当我用 strace 运行同一个程序时,我可以看到:所有对 brk 的调用都在增加,并且对 munmap 的调用(就大小而言)加起来没有达到 mmap-ed 的数量(和如上所示)。更糟糕的是,随着我的进程进行后台工作,VSZ 随着时间的推移缓慢增加,并且日志显示 (***) 在记录这些统计信息时相应增加

所以我的问题是:这个值代表什么?我的记忆是否被释放?我可以做些什么来防止这种消费增长?

解决方法

这个值代表什么?

它表示 TCMalloc 告诉系统它不需要并且系统可以用于其他目的的内存量。

我的记忆是否被释放?

没有。操作系统已经决定让它自由只是在程序需要时再次使用它是浪费精力,而是决定在一个步骤中直接将其从一种用途切换到另一种用途,而不是经历两次努力让它免费只是为了让它不免费使用它。

我能做些什么来阻止这种消费增长?

你为什么要这样做?如果程序稍后需要内存,它只会更容易,最大限度地减少系统空闲列表上的争用,并且根本没有有害影响。 TCMalloc 已告诉操作系统(通过 madvise(DONTNEED)),操作系统可能会恢复内存,并且操作系统已经做出决定,让它自由只是在需要时再次使用它并不是一个好主意。您是否有充分的理由认为操作系统是错误的?

在一个步骤中直接将内存从一个我们转移到另一个我们要容易得多,而不是通过两个步骤将其释放出来以便再次使用它。空闲列表可能会在负载下竞争,不使用它要简单得多。

您可以通过运行一些消耗大量内存然后终止的程序来强制操作系统释放它。这将强制操作系统将内存转移到该进程,然后在该进程终止时释放它。但这根本不会带来任何好处,并且为了最终增加内存管理器中的争用需要付出很多努力。这里没有问题。