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

调用GLib中g_bus_get_sync为何出现内存泄漏?

g_bus_get_sync 检测到疑似内存泄漏,是否是我的操作有误?

我编写了以下代码,编译后用Valgrind检测,发现g_bus_get_sync似乎存在内存泄漏,请问是我哪里操作错了吗?

#include <gio/gio.h>
#include <libmm-glib.h>

static gboolean loop_ready(GMainLoop *loop)
{
    g_main_loop_quit(loop);
    return G_SOURCE_REMOVE;
}

int main(int argc, char *argv[])
{
    g_autoptr(GDBusConnection)  connection = NULL;
    g_autoptr(GError)           error = NULL;

    connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
    if (!connection) {
        g_printerr("Error: %s\n", error->message);
    }

    // EDIT: Added g_dbus_connection_close_sync at suggestion of @user7860670
    g_dbus_connection_close_sync(connection);
    g_clear_object(&connection);

    {
        g_autoptr(GMainLoop) loop = NULL;

        loop = g_main_loop_new(NULL, FALSE);
        g_idle_add((GSourceFunc)loop_ready, loop);
        g_main_loop_run(loop);
    }
}

Valgrind命令:

valgrind --tool=memcheck --suppressions=/usr/share/glib-2.0/valgrind/glib.supp --leak-check=full ./memtest

Valgrind检测结果:

==178041== Memcheck, a memory error detector
==178041== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==178041== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==178041== Command: ./memtest
==178041== 
==178041== 
==178041== HEAP SUMMARY:
==178041==     in use at exit: 104,240 bytes in 1,190 blocks
==178041==   total heap usage: 2,299 allocs, 1,109 frees, 238,311 bytes allocated
==178041== 
==178041== 304 bytes in 1 blocks are possibly lost in loss record 946 of 969
==178041==    at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==178041==    by 0x40147D9: calloc (rtld-malloc.h:44)
==178041==    by 0x40147D9: allocate_dtv (dl-tls.c:375)
==178041==    by 0x40147D9: _dl_allocate_tls (dl-tls.c:634)
==178041==    by 0x4EC4834: allocate_stack (allocatestack.c:430)
==178041==    by 0x4EC4834: pthread_create@@GLIBC_2.34 (pthread_create.c:647)
==178041==    by 0x4B53504: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7200.4)
==178041==    by 0x4B2ECCC: g_thread_new (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7200.4)
==178041==    by 0x4AFF616: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7200.4)
==178041==    by 0x49207D7: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.7200.4)
==178041==    by 0x4920884: g_task_get_type (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.7200.4)
==178041==    by 0x498C288: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.7200.4)
==178041==    by 0x4980020: g_bus_get_sync (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.7200.4)
==178041==    by 0x1093AE: main (memtest.cpp:15)
==178041== 
==178041== 304 bytes in 1 blocks are possibly lost in loss record 947 of 969
==178041==    at 0x484DA83: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==178041==    by 0x40147D9: calloc (rtld-malloc.h:44)
==178041==    by 0x40147D9: allocate_dtv (dl-tls.c:375)
==178041==    by 0x40147D9: _dl_allocate_tls (dl-tls.c:634)
==178041==    by 0x4EC4834: allocate_stack (allocatestack.c:430)
==178041==    by 0x4EC4834: pthread_create@@GLIBC_2.34 (pthread_create.c:647)
==178041==    by 0x4B53504: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7200.4)
==178041==    by 0x4B2ECCC: g_thread_new (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7200.4)
==178041==    by 0x49762D9: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.7200.4)
==178041==    by 0x497FFF3: g_bus_get_sync (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.7200.4)
==178041==    by 0x1093AE: main (memtest.cpp:15)
==178041== 
==178041== LEAK SUMMARY:
==178041==    definitely lost: 0 bytes in 0 blocks
==178041==    indirectly lost: 0 bytes in 0 blocks
==178041==      possibly lost: 608 bytes in 2 blocks
==178041==    still reachable: 64,442 bytes in 533 blocks
==178041==         suppressed: 26,374 bytes in 533 blocks
==178041== Reachable blocks (those to which a pointer was found) are not shown.
==178041== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==178041== 
==178041== For lists of detected and suppressed errors, rerun with: -s

解答

从Valgrind的栈回溯可以看出,这些“疑似泄漏”的内存并非g_bus_get_sync本身的问题,而是GIO内部创建的后台线程的TLS(线程本地存储)资源。具体原因和解决方式如下:

  1. 泄漏本质分析

    • 标记为“possibly lost”的内存是pthread_create时分配的线程本地存储结构,这类内存在线程正常退出时会由操作系统自动回收,但Valgrind无法跟踪到库内部线程的释放路径,因此误标记为疑似泄漏。
    • 你的代码本身没有错误:g_autoptr已经正确管理了GDBusConnection的生命周期,手动调用g_dbus_connection_close_sync和g_clear_object也没问题,但GLib内部的后台线程需要时间完成清理。
  2. 消除Valgrind报告的方法

    • 方法一:让GLib完成线程清理
      在释放连接后,添加主循环迭代,给后台线程处理收尾工作的时间:
      g_clear_object(&connection);
      // 处理所有pending事件,确保后台线程退出
      while (g_main_context_iteration(NULL, FALSE));
      
    • 方法二:添加抑制规则
      如果确认这些是假阳性报告,可以在Valgrind的抑制文件中添加规则,忽略这类线程TLS相关的泄漏:
      {
          name: glib-thread-tls
          Memcheck:Leak
          match-leak-kinds: possibly
          fun: calloc
          fun: allocate_dtv
          fun: _dl_allocate_tls
          fun: allocate_stack
          fun: pthread_create@@GLIBC_2.34
          fun: g_thread_new
      }
      
    • 方法三:忽略假阳性
      程序退出时操作系统会回收所有进程内存,这类“possibly lost”的内存不会造成实际的内存泄漏问题,无需刻意处理。
  3. 额外建议

    • 不需要手动调用g_clear_object,g_autoptr会在变量作用域结束时自动释放对象;
    • g_bus_get_sync返回的是共享的DBus连接,GLib会缓存该连接,即使你关闭自己的引用,缓存中的连接可能仍会保留到程序退出,这是正常行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 22:38:05