g++ -static 导致内存泄漏(由 mtrace 报告)

3

我遇到了一个奇怪的问题,希望有人能够解决......我有以下代码:

#include <unistd.h>
#include <mcheck.h>
#include <pthread.h>

static void *run(void *args)
{
  sleep(1);
  return NULL;
}

int main()
{
  mtrace();
  pthread_t thread;
  pthread_create(&thread, NULL, run, NULL);
  pthread_join(thread, NULL);

  return 0;
}

我已经以这两种方式编译了它:

g++ -static program.cpp -lpthread

并且

g++ program.cpp -ltpthread

当我查看mtrace的输出(在我的情况下是mem.out)时,如果我使用-static选项,mtrace会报告以下内容:
Memory Not freed:
__________________
   Address      Size   Caller
   0x085ac350   0x88   program.cpp:0

但是当我排除 -static 选项时,mtrace报告如下:
No memory leaks.

那么这里发生了什么事情,您有什么想法吗?

不确定-static是做什么的,但可能是静态分配的东西在mtrace报告泄漏后被释放。我记得使用_CrtDumpMemoryLeaks()时也发生了同样的事情。 - Barış Uşaklı
1
你的运行函数为什么没有任何返回值? - ForEveR
1
@KerrekSB - 噗,你从没听说过“int void”类型?真是个菜鸟... 另外,我已经修复了。 - poy
如果您运行Valgrind,是否会得到相同的结果? - André Oriani
1
应该是 extern "C" void* run(void* args),并且仍然需要返回 NULL 以避免与未定义行为交互。 - Martin York
显示剩余13条评论
1个回答

2
这是在我的常规桌面Linux系统(FC-17)上复制此问题的步骤:

以下是步骤:

#include <mcheck.h>
#include <pthread.h>

extern "C" { static void *run(void *) { return 0; } }

int main() {
  mtrace();
  pthread_t thread;
  pthread_create(&thread, 0, run, 0);
  pthread_join(thread, 0);
  return 0;
}

使用命令g++ -g -static -pthread编译。以下是我执行它并得到mtrace错误的方式:

$ MALLOC_TRACE=mt.txt mtrace ./a.out mt.txt

Memory not freed:
-----------------
           Address     Size     Caller
0x00000000011a9c90    0x110  at 0x43d7f9

我有一个64位的系统,因此大小不匹配。在gdb中反汇编地址时,它会给出以下结果:

(gdb) disass 0x43d7f9
Dump of assembler code for function _dl_allocate_tls:
   0x000000000043d7c0 <+0>:     mov    %rbx,-0x20(%rsp)
   0x000000000043d7c5 <+5>:     mov    %rbp,-0x18(%rsp)
...
   0x000000000043d7f4 <+52>:    callq  0x428150 <calloc>
   0x000000000043d7f9 <+57>:    test   %rax,%rax
   0x000000000043d7fc <+60>:    je     0x43d8e0 <_dl_allocate_tls+288>
...

看起来为每个线程分配了一些线程本地存储。似乎是每个线程的一次性分配,因为在join之后添加了一个pthread_create调用时没有进行额外的分配,而在join之前添加时则进行了一次分配。_dl_allocate_tls表明这通常是在动态链接期间调用的函数,但似乎在线程堆栈初始化期间被调用。通过glibc代码的grep显示它被调用在allocate_stack.c中。
在glibc中确实有相应的_dl_deallocate_tls调用,因此我认为这个错误是无害的。valgrind没有检测到任何内存泄漏。

有趣的是valgrindmtrace对情况的看法不同。 - poy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接