GTK4 Windows多文件选择内存泄漏与崩溃问题求助
问题分析与修复方案
你的代码存在多个致命内存操作错误,直接引发段错误与GLib断言失败,以下是问题点及修复后的代码:
核心错误点
- 未初始化的GtkTextIter指针:声明
GtkTextIter *start;后未分配内存,直接传给gtk_text_buffer_get_start_iter会写入随机内存,触发内存损坏。 - 字符串越界写入:
sprintf(path, "%s\n", path);往g_file_get_path返回的固定长度字符串中追加换行符,破坏堆内存,导致GLib内部哈希表操作失败(即那些断言错误的根源)。 - 未释放GFile实例:每次
g_list_model_get_item获取的GFile对象未调用g_object_unref,造成内存泄漏。 - 未释放GListModel:
gtk_file_dialog_open_multiple_finish返回的GListModel用完后未调用g_object_unref。 - path变量内存泄漏:循环中每次
g_file_get_path返回的字符串未及时g_free,仅在最后释放一次,导致多次泄漏。 - 提前释放GtkFileDialog:异步操作未完成就
g_object_unref(fd),虽Gtk异步方法会临时持有引用,但规范做法是在回调中处理释放。
修复后的代码
static void choseTargetFinish (GObject* source_object, GAsyncResult* res, gpointer data) { GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object); GError *error = NULL; GListModel *files = gtk_file_dialog_open_multiple_finish(dialog, res, &error); if (error != NULL) { g_warning("Failed to open files: %s", error->message); g_error_free(error); g_object_unref(dialog); return; } if (files != NULL) { // 使用栈上的GtkTextIter实例,替代未初始化的指针 GtkTextIter start, end; gtk_text_buffer_get_start_iter(targetPathBuffer, &start); gtk_text_buffer_get_end_iter(targetPathBuffer, &end); gtk_text_buffer_delete(targetPathBuffer, &start, &end); guint n_items = g_list_model_get_n_items(files); for (guint i = 0; i < n_items; i++) { GFile *file = g_list_model_get_item(files, i); if (file == NULL) continue; char *path = g_file_get_path(file); if (path != NULL) { // 用g_strconcat安全拼接换行符,避免越界 char *path_with_newline = g_strconcat(path, "\n", NULL); gtk_text_buffer_insert(targetPathBuffer, &end, path_with_newline, -1); gtk_text_buffer_get_end_iter(targetPathBuffer, &end); g_free(path_with_newline); g_free(path); } // 释放GFile对象 g_object_unref(file); } // 释放GListModel g_object_unref(files); } // 在回调末尾释放对话框对象 g_object_unref(dialog); } static void chooseTarget_cb (GtkWidget *widget) { GtkFileDialog *fd = gtk_file_dialog_new(); gtk_file_dialog_open_multiple(fd, NULL, NULL, choseTargetFinish, NULL); // 不再提前unref,交给回调处理释放 }
关键修改说明
- GtkTextIter改为栈实例:用
GtkTextIter start, end;替代指针,传地址给gtk_text_buffer_get_*_iter,避免野指针访问。 - 安全拼接字符串:用
g_strconcat创建带换行符的新字符串,不破坏原路径字符串的内存。 - 循环内释放资源:每次获取的GFile和path都在循环内释放,避免内存泄漏。
- 添加错误处理:用
GError捕获异步操作错误,便于调试。 - 规范释放对话框:将
g_object_unref(dialog)放在回调末尾,确保异步操作完成后再释放对象。
内容的提问来源于stack exchange,提问作者Yonett
相关产品推荐
相关产品推荐

