【问题标题】:Thrown exceptions being leaked in C++在 C++ 中泄露的抛出异常
【发布时间】:2014-09-30 21:36:49
【问题描述】:

我在玩弄 C++,其中有一段“可重新启动”的代码。也就是说:

class handler {
public:
    virtual ~handler() {}
    virtual response handle(request &req) = 0;
};

response dispatch(request &req, handler &hnd) {
    try {
        return(hnd.handle(req));
    } catch(handler &rep) {
        return(dispatch(req, rep));
    }
}

然后,在另一部分代码中:

static response serve(request &req) {
    throw(resp::message("Merdel", {"Test"}));
}

其中resp::messagehandler 的子类。

这似乎工作正常,但是当我用 Valgrind 运行它时,它告诉我这会泄漏内存:

==2609== 352 bytes in 11 blocks are definitely lost in loss record 12 of 16
==2609==    at 0x4C270FE: memalign (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2609==    by 0x4010BEF: tls_get_addr_tail (dl-tls.c:529)
==2609==    by 0x401110F: __tls_get_addr (dl-tls.c:767)
==2609==    by 0x668FC9B: __cxa_get_globals (eh_globals.cc:63)
==2609==    by 0x668F5EE: __cxa_allocate_exception (eh_alloc.cc:132)
==2609==    by 0x61DDA5E: serve(arw::request&) (arwtest.ashc:7)
==2609==    by 0x640E18B: arw::funhandler::handle(arw::request&) (arw.cpp:95)
==2609==    by 0x640E1C5: arw::dispatch(arw::request&, arw::handler&) (arw.cpp:100)
==2609==    by 0x640E487: arw::dispatch(ashd::request const&, arw::handler&) (arw.cpp:119)
==2609==    by 0x61DDBA7: _htstart (arwtest.ashc:11)
==2609==    by 0x403CCD: servehtstart (request.c:228)
==2609==    by 0x4040C5: servereq (request.c:303)

serve(arw::request&) (arwtest.ashc:7) 是上面列出的serve 函数。

为什么会泄漏内存?我的理解是 C++ 运行时应该自动为我释放这些异常(而且我也没有能力手动释放它们,对吧?),那么是什么原因导致它不释放呢?

我确实找到了 these two 以前关于类似主题的问题,但它们似乎不适用于这里,因为它们仅在特殊情况下处理单个泄漏的异常,而此代码会泄漏每个请求的异常(请注意,有 11 个单独的块被泄露;这是因为我在此测试期间运行了此测试功能 11 次。

编辑:我不知道它是否相关,但可能值得注意的是,回溯中的servehtstartservereq 是纯C 程序中的函数。 _htstart 及以上是来自dlopen()ed 共享对象的 C++ 代码。也可能相关的是,只有此共享对象的 dlopen 才能将 libstdc++ 带入进程。

【问题讨论】:

  • 你的节目结局如何?
  • @quantdev:此特定代码在单独的线程中运行,该线程在servereq 返回后终止。在此示例中,每个线程都会引发这些异常之一。程序作为一个整体结束,因为我发送它SIGTERM,它捕获并退出运行它的线程中的主循环。另外,请参阅问题的编辑。
  • 线程本地存储没有被清理。这可能没问题。
  • @DavidSchwartz:如果我创建的每个线程都有泄漏,这似乎不太好。如何确保 TLS 得到清理?
  • @Dolda2000 检查堆栈中显示的函数,看看它们何时/如何分配 TLS 以及何时/如何清理它。

标签: c++ memory-leaks


【解决方案1】:

事实证明,这是 glibc 某些版本中的一个错误,包括目前在 Debian Stable 中的版本(即 2.13),但此后已修复。在 Debian 测试设置(使用 glibc 2.19)上运行相同的程序时,不会发生内存泄漏。

显然,glibc 2.13 没有正确清理由dlopen()'ed 对象引入的线程本地内存。它出现在这里是因为 libstdc++ 仅作为 dlopen() 的结果加载。这个问题之前在这两个错误报告中有所描述:

解决问题的 glibc 提交是 e6c61494

感谢@quantdev,@DavidSchwartz。您的 cmets 让我意识到要寻找什么。

【讨论】:

    猜你喜欢
    • 2014-12-15
    • 2014-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-22
    • 2011-04-10
    相关资源
    最近更新 更多