You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

对Valgrind Massif输出存疑:free函数下出现内存分配记录

关于Massif分析中free调用链出现内存分配记录的疑问解答

我尝试使用Massif分析某应用的堆内存使用情况,运行时添加了--pages-as-heap=true选项,对输出内容存在疑惑。我发现free函数相关调用链中出现了内存分配记录——我认为free不应触发内存分配。以下是部分输出(敏感/无关内容已省略):

1| ->35.94% (2,952,790,016B) 0x656C2A2: new_heap (in /usr/lib64/libc.so.6)
2| | ->35.94% (2,952,790,016B) 0x656CF2A: arena_get2.part.0 (in /usr/lib64/libc.so.6)
3| |   ->35.94% (2,952,790,016B) 0x656F6B0: tcache_init.part.0 (in /usr/lib64/libc.so.6)
4| |     ->24.50% (2,013,265,920B) 0x656FE1D: malloc (in /usr/lib64/libc.so.6)
5| |     | ->24.50% (2,013,265,920B) 0x6265CBB: operator new(unsigned long) (in  /usr/lib64/libstdc++.so.6.0.29)
6| |     |   ->17.15% (1,409,286,144B) 0x462D39: std::__detail::_MakeUniq<grpc::ClientContext>::__single_object std::make_unique<grpc::ClientContext>() (unique_ptr.h:1077)
--
--
--
7| |     |   | |                                         
8| |     |   | ->00.82% (67,108,864B) in 1+ places, all below ms_print's threshold (01.00%)
9| |     |   | 
10| |     |   ->01.63% (134,217,728B) 0x42D6A0: void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) (basic_string.tcc:229)
11| |     |   | ->01.63% (134,217,728B) 0x428E16: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&) (basic_string.h:654)
12| |     |   |   ->01.63% (134,217,728B) in 2 places, all below massif's threshold (1.00%)
13| |     |   |     
14| |     |   ->00.82% (67,108,864B) in 1+ places, all below ms_print's threshold (01.00%)
15| |     |   
16| |     ->11.43% (939,524,096B) 0x657033E: free (in /usr/lib64/libc.so.6)
17| |       ->11.43% (939,524,096B) 0x48531D0: grpc_core::(anonymous namespace)::ThreadInternalsPosix::ThreadInternalsPosix(char const*, void (*)(void*), void*, bool*, grpc_core::Thread::Options const&)::{lambda(void*)
18| |         ->11.43% (939,524,096B) 0x6560199: start_thread (in /usr/lib64/libc.so.6)
19| |           ->11.43% (939,524,096B) 0x65E4533: clone (in /usr/lib64/libc.so.6)

我能理解第2行的arena分配以及第4、5行的malloc/new分配,但不明白第16行的free及其下方调用链的含义,希望得到解答。

核心原因解释

1. --pages-as-heap=true的统计范围影响

这个选项会让Massif把系统中所有内存页都纳入堆内存统计,包括glibc内存分配器内部的元数据内存(比如线程缓存tcache、分配arena的结构内存),而默认情况下Massif只统计应用主动调用malloc/new分配的内存。

2. tcache_init的懒加载触发逻辑

glibc的tcache(线程本地缓存)是懒初始化的:当线程**第一次调用free**时,才会触发tcache_init,这个初始化过程需要分配内存来构建缓存的管理结构,因此会调用底层的new_heap、arena_get2等分配函数。

3. 调用链的实际含义

第16-19行的调用链不是说free主动发起了内存分配,而是触发tcache初始化的那个free调用的上下文:

  • 这个939MB的内存分配是tcache_init过程中分配的元数据内存
  • 触发这次初始化的是grpc线程创建流程中的某个free调用,所以Massif将分配的调用栈回溯到了这个free的调用上下文里

验证方法

可以关闭--pages-as-heap=true重新运行Massif,这部分关联到free的分配记录会消失——因为默认模式下Massif不会统计glibc分配器内部的元数据内存。

内容的提问来源于stack exchange,提问作者Kevin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 03:43:17