Valgrind在测试程序中未检测到getinterfaceip函数的内存泄漏
Valgrind内存泄漏排查疑问
问题场景
主程序运行时Valgrind报告了内存泄漏,但将getinterfaceip的逻辑复制到简单C测试程序中用Valgrind检测时,却未发现任何泄漏。想确认该泄漏是否真的来自getinterfaceip函数。
Valgrind泄漏报告
==51== 200 bytes in 1 blocks are definitely lost in loss record 348 of 417 ==51== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==51== by 0x508CF54: __libc_alloc_buffer_allocate (alloc_buffer_allocate.c:26) ==51== by 0x5130628: alloc_buffer_allocate (alloc_buffer.h:143) ==51== by 0x5130628: __resolv_conf_allocate (resolv_conf.c:411) ==51== by 0x512DE21: __resolv_conf_load (res_init.c:592) ==51== by 0x5130232: __resolv_conf_get_current (resolv_conf.c:163) ==51== by 0x512E3D4: __res_vinit (res_init.c:614) ==51== by 0x512F5CF: maybe_init (resolv_context.c:122) ==51== by 0x512F5CF: context_get (resolv_context.c:184) ==51== by 0x512F5CF: context_get (resolv_context.c:176) ==51== by 0x512F5CF: __resolv_context_get (resolv_context.c:195) ==51== by 0x511E63F: gethostbyname (getXXbyYY.c:105) ==51== by 0x153745: getinterfaceip (sctpThread.cpp:72) ==51== by 0x153745: startPrometheus(sctp_params&) (sctpThread.cpp:539) ==51== by 0x145051: main (sctpThread.cpp:608)
主程序相关源码
char* getinterfaceip() { char hostname[256]; char *IP; struct hostent *host_entry; int retVal; retVal = gethostname(hostname, sizeof(hostname)); if ( retVal == -1 ) return NULL; host_entry = gethostbyname(hostname); if ( host_entry == NULL ) return NULL; IP = inet_ntoa(*((struct in_addr*) host_entry->h_addr_list[0])); return IP; } void startPrometheus(sctp_params_t &sctpParams) { auto podName = std::getenv("POD_NAME"); string metric = "E2TBeta"; if (strstr(podName, "alpha") != NULL) { metric = "E2TAlpha"; } //Get eth0 interface IP char* host = getinterfaceip(); string hostip = host; sctpParams.prometheusFamily = &BuildCounter() .Name(metric.c_str()) .Help("E2T instance metrics") .Labels({{"POD_NAME", sctpParams.podName}}) .Register(*sctpParams.prometheusRegistry); string prometheusPath; if (hostip.empty()) prometheusPath = sctpParams.prometheusPort + "," + "[::]:" + sctpParams.prometheusPort; }
测试程序源码
#include<stdio.h> #include <unistd.h> #include <stdlib.h> #include <pthread.h> #include <sys/time.h> #include <sys/inotify.h> #include <errno.h> #include <sys/stat.h> #include <arpa/inet.h> #include <netdb.h> main() { char hostname[256]; char *IP; struct hostent *host_entry; int retVal; retVal = gethostname(hostname, sizeof(hostname)); if ( retVal == -1 ) return NULL; host_entry = gethostbyname(hostname); if ( host_entry == NULL ) return NULL; IP = inet_ntoa(*((struct in_addr*) host_entry->h_addr_list[0])); printf("%s", IP); sleep(300); }
结论与分析
- 泄漏确实和
getinterfaceip的调用有关,但并非函数本身的代码问题,而是触发了libc内部解析器的内存分配:- Valgrind调用栈清晰显示,泄漏发生在
gethostbyname内部的__resolv_conf_allocate等glibc内部函数中,getinterfaceip是触发这个调用链的入口。
- Valgrind调用栈清晰显示,泄漏发生在
- 测试程序和主程序的差异导致Valgrind报告不同:
- 测试程序是短期运行进程,退出时操作系统会回收所有进程内存,Valgrind默认会忽略进程退出时的内存泄漏(因为这类泄漏不会长期占用系统资源)。
- 主程序是长期运行的服务进程,不会快速退出,glibc为DNS解析分配的内部缓存内存(比如resolv.conf相关结构)没有被主动释放,因此Valgrind会报告为明确泄漏。
- 额外说明:
inet_ntoa返回的是静态缓冲区指针,不需要手动释放,这部分无泄漏;gethostbyname返回的host_entry是libc内部缓存,也不需要手动free。
- 解决建议:
- 若使用glibc,可尝试调用
res_nclose重置解析器上下文,释放内部缓存,但注意这可能影响其他依赖DNS解析的代码。 - 替换为现代线程安全API
getaddrinfo,它的内存管理更透明,可通过freeaddrinfo手动释放资源,避免这类内部缓存泄漏。
- 若使用glibc,可尝试调用
内容的提问来源于stack exchange,提问作者ravi
相关产品推荐
相关产品推荐

