我編寫了一個簡單的程序模塊來詢問用戶配置文件名稱。爲此,我使用條目窗口小部件創建窗口,並在網格中組織兩個按鈕(確定和取消)。當用戶輸入一個已經存在的配置文件名稱時,通過創建對話框「ok」按鈕來告訴他這個事實,並且在他按下它之後,它回到選擇配置文件名稱(窗口不隱藏也不被銷燬) 。問題是,當我創建一個配置文件,然後在配置文件名稱選擇器和對話框上發送ok按鈕(通過在輸入鍵上放置重要的東西並打算泡茶),(創建和銷燬對話框進行簡單循環)程序的內存使用量增加。對話框創建和銷燬循環增加內存使用
TL; DR 只需創建和銷燬GTK窗口(和對話)似乎引起了內存泄漏。將應用程序放在循環中使其將內存使用量增加約1900%(從10mb增加到200mb)。
不,我沒有使用爲它設計的應用程序測試內存泄漏。 是的,我設置了G_SLICE = always-malloc。 是的,有另一個線程在程序的後臺運行(但我確定它不會導致任何泄漏) 如果您想要了解內存中發生的更多信息,可以從Windows性能監視器發佈屏幕。
問題是 - 它是由我造成的內存泄漏,還是GTK的錯誤(我聽說它有一個懶惰的內存管理策略,但在一段時間內存使用量從200mb下降到140mb並停留在那裏)?
下面的代碼:
// This callback racts to the ok and cancel buttons. If input was correcs
// or the user pressed cancel it destroys the window. Else it show error
// prompt. The showing error prompt seems to be the problem here.
void pickNameButtCB(GtkWidget *button, gpointer *call)
{
GtkWidget *window = gtk_widget_get_toplevel(button);
if(*((char*)call) == 'k')
{
GList *entryBase = gtk_container_get_children(GTK_CONTAINER(gtk_bin_get_child(GTK_BIN(window)))), *entry = entryBase;
for(size_t i=g_list_length(entry); i>0 && !GTK_IS_ENTRY(entry->data); --i)
entry = g_list_next(entry);
if(gtk_entry_get_text_length(GTK_ENTRY(entry->data)) > 0)
{
const char *temp = gtk_entry_get_text(GTK_ENTRY(entry->data));
char path[266];
strcpy(path, settingsDir);
strcat(path, temp);
strcat(path, ".prof");
if(settProfExists(path))
{
g_list_free(entryBase);
showError(GTK_WINDOW(window), GTK_MESSAGE_ERROR, "Profile with that name already exists!");
return;
}
// nothing here executes as well
}
else
{
/** doesn't execute when the memory leak happens */
}
g_list_free(entryBase);
}
gtk_widget_destroy(window);
gtk_main_quit();
}
void showError(GtkWindow *parent, GtkMessageType type, const char *str)
{
GtkWidget *window = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_OK, str);
g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window);
gtk_dialog_run(GTK_DIALOG(window));
}
bool settProfExists(const char *path)
{
if(fileExists(path))
return true;
return false;
}
bool fileExists(const char *path)
{
struct stat info;
errno = 0;
if((stat(path, &info)) != 0)
if(errno == ENOENT)
return false;
return true;
}
「調試我的代碼爲我」是不是一個好問題。從你的代碼中消除多餘的細節開始,直到你達到[mcve]。你可能會一路發現問題。 – StoryTeller
我看到你創建窗口的函數,但是我沒有看到任何實際創建或銷燬任何窗口。 –
@JohnBollinger「chooseProfName」在這裏只是爲了完整。它確實創建了循環中不斷打開的窗口。在pickNameButtCB中運行該循環,運行showError,創建對話框並將其銷燬(我將「響應」信號連接到小部件銷燬函數)。 – Grabusz