对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
相关产品推荐
相关产品推荐

