fix(dfm-io): drain GLib deferred callbacks after g_file_enumerate_chi…#321
Conversation
…ldren g_file_enumerate_children() internally creates and destroys temporary GDBusProxy instances (mount tracker proxy, daemon proxy) whose finalization defers the weak_ref_free callback to the thread-default GMainContext via call_destroy_notify() as a g_idle_source. In a QThread without a GLib main loop, these idle sources are never dispatched, causing the GWeakRef allocations (8 bytes each from gdbusproxy.c:112) to leak. Iterate the thread-default GMainContext immediately after the GVFS enumeration call to process the deferred callbacks while still on the same thread. Log: Fixed 8-byte GWeakRef memory leak triggered by GVFS trash enumeration. Assisted-by: deepseek-v4-pro Influence: 1. Enumerate trash:/// under Valgrind — verify zero definitely-lost bytes at weak_ref_new 2. Test trash directory traversal with daemon running and file manager not in background 3. Verify normal file enumeration (local paths) is unaffected 4. Verify enumerate with timeout (QtConcurrent path) is unaffected 5. Verify rapid open/close of trash window does not accumulate leaks fix(dfm-io): 在 g_file_enumerate_children 后处理 GLib 延迟回调,修复 GWeakRef 泄露 g_file_enumerate_children() 内部会创建并销毁临时的 GDBusProxy 实例 (mount tracker proxy 和 daemon proxy),其析构时通过 call_destroy_notify() 将 weak_ref_free 回调以 g_idle_source 的形式 挂载到线程默认的 GMainContext。在没有 GLib 主循环的 QThread 中, 这些 idle source 永远不会被调度,导致 GWeakRef 分配(每次 8 字节, 来自 gdbusproxy.c:112)泄露。 在 GVFS 枚举调用返回后立即迭代线程默认的 GMainContext, 在同一个线程上处理延迟回调,避免泄露。 Log: 修复 GVFS 回收站枚举时触发的 8 字节 GWeakRef 内存泄露。 Influence: 1. Valgrind 下枚举 trash:/// — 验证 weak_ref_new 处零 definitely lost 2. 测试 daemon 运行且文件管理器未驻留时回收站目录遍历 3. 验证普通本地文件枚举不受影响 4. 验证带超时的枚举(QtConcurrent 路径)不受影响 5. 验证快速打开/关闭回收站窗口不累积泄露
There was a problem hiding this comment.
Sorry @liujianqiang-niu, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
deepin pr auto review★ 总体评分:100分■ 【总体评价】
■ 【详细分析】
■ 【改进建议代码示例】 // 当前代码已为最佳实践,无需修改,此处展示其在完整上下文中的标准形态
bool DEnumeratorPrivate::createEnumerator(const QUrl &url, QPointer<DEnumerator> me) {
// ... 前置逻辑 ...
GError *gerror = nullptr;
GFileEnumerator *genumerator = g_file_enumerate_children(gfile,
enumLinks ? G_FILE_QUERY_INFO_NONE : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
&gerror);
// g_file_enumerate_children internally creates and destroys temporary
// GDBusProxy instances (mount tracker proxy, daemon proxy). During proxy
// finalization, g_dbus_connection_signal_unsubscribe defers the
// user_data_free_func (weak_ref_free) to the thread-default GMainContext
// via call_destroy_notify() — a g_idle_source. Process it now while we
// are on the same thread, otherwise the GWeakRef (8 bytes from
// gdbusproxy.c:112) leaks when no GLib main loop runs on this QThread.
// See: glib2.0/gio/gdbusconnection.c:signal_subscriber_unref → call_destroy_notify
GMainContext *ctx = g_main_context_get_thread_default();
if (ctx)
g_main_context_iteration(ctx, TRUE);
if (!me) {
// Clean up the enumerator if it was created but the object is no longer valid
if (genumerator) {
g_object_unref(genumerator);
genumerator = nullptr;
}
// ... 后置错误处理逻辑 ...
}
// ... 后续逻辑 ...
} |
|
稳定泄露复现方式,安装完镜像后,后台并未运行/usr/libexec/dde-file-manager,手动终端运行:valgrind --leak-check=full --show-leak-kinds=all --num-callers=50 --track-origins=yes --log-file=/home/uos/work-ljq/work-v25/code-work/work/valgrind.log /usr/libexec/dde-file-manager -n "/home/uos/work-ljq/" |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Johnson-zs, liujianqiang-niu, liyigang1 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
…ldren
g_file_enumerate_children() internally creates and destroys temporary GDBusProxy instances (mount tracker proxy, daemon proxy) whose finalization defers the weak_ref_free callback to the thread-default GMainContext via call_destroy_notify() as a g_idle_source. In a QThread without a GLib main loop, these idle sources are never dispatched, causing the GWeakRef allocations (8 bytes each from gdbusproxy.c:112) to leak.
Iterate the thread-default GMainContext immediately after the GVFS enumeration call to process the deferred callbacks while still on the same thread.
Log: Fixed 8-byte GWeakRef memory leak triggered by GVFS trash enumeration.
Assisted-by: deepseek-v4-pro
Influence:
fix(dfm-io): 在 g_file_enumerate_children 后处理 GLib 延迟回调,修复 GWeakRef 泄露
g_file_enumerate_children() 内部会创建并销毁临时的 GDBusProxy 实例 (mount tracker proxy 和 daemon proxy),其析构时通过
call_destroy_notify() 将 weak_ref_free 回调以 g_idle_source 的形式 挂载到线程默认的 GMainContext。在没有 GLib 主循环的 QThread 中,
这些 idle source 永远不会被调度,导致 GWeakRef 分配(每次 8 字节,
来自 gdbusproxy.c:112)泄露。
在 GVFS 枚举调用返回后立即迭代线程默认的 GMainContext,
在同一个线程上处理延迟回调,避免泄露。
Log: 修复 GVFS 回收站枚举时触发的 8 字节 GWeakRef 内存泄露。
Influence: