使用多个图像的GTK2应用程序内存泄漏

这是关于GTK2处理资源使用的最后一个问题的后续内容。

应用程序正在正确显示图像,但是现在每次从磁盘加载GtkImages并将其放置在固定帧上进行绝对定位时,它似乎会泄漏一些内存。

我使用以下几秒钟调用的基本方法来加载和显示不同的图像集。

 int DisplaySymbols( GameInfo *m ) { // variable declarations removed for brevity // error checking needs to be added GtkWidget *image; pos_y = 150; for( y = 0; y < 3; y++ ) { pos_x = 187; for( x = 0; x < 5; x++ ) { image=gtk_image_new_from_file( fileName ); gtk_fixed_put(GTK_FIXED(frame), image, pos_x, pos_y); pos_x += symbols[i].pixel_width; } pos_y += symbols[i].pixel_height; } gtk_widget_show_all(window); return( 0 ); } 

我已经阅读了有关资源使用情况的部分GTK+文档,我只是无法弄清楚如何使用API调用来防止内存泄漏。

我有一些想法和/或问题:

  • 我是否应该在固定框架中创建一些图像保持小部件,以便更轻松地管理放置在框架中的图像?
  • 我的代码在做什么或不做什么导致内存被泄露? 我可能不会发布GtkImage小部件?
  • 每次我需要使用它们时,从磁盘加载图像似乎有点低效。 如何将它们读入内存,然后根据需要在框架中显示它们?

部分源代码如下:

 //Compile me with: gcc -o leak leak.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0) // include files removed for brevity /* GTK */ #include  #include  typedef struct { unsigned int pixel_width, pixel_height; gchar fileName[20]; }symbol_t; static symbol_t symbols[] = { /* only showing 2 of eight - brevity */ { 118, 107, "images/LO.jpg" }, { 118, 107, "images/L1.jpg" } }; typedef struct { char SpinResult[3][5]; // index of images pointing into symbols struct }GameInfo; GameInfo egm; GtkWidget *frame; /* for absolute positionining of widgets */ GtkWidget *window; /**** prototypes ****/ // remove for brevity /********************/ // init random number generator int Init( void ) { // create random number - brevity } // Determine spin outcome and store into egm.SpinResult array int DoSpin( GameInfo *egm ) { // generate matrix of indexes into symbols structure // so we know what symbols to display in the frame } int DisplaySymbols( GameInfo *egm ) { // variable declarations removed - brevity GtkWidget *image; pos_y = 150; for( y = 0; y < 3; y++ ) { pos_x = 187; for( x = 0; x < 5; x++ ) { image = gtk_image_new_from_file( symbols[i].fileName ); gtk_fixed_put(GTK_FIXED(frame), image, pos_x, pos_y); pos_x += symbols[i].pixel_width; } pos_y += symbols[i].pixel_height; } gtk_widget_show_all(window); return( 0 ); } void btnSpin_clicked(GtkWidget *button, gpointer data) { DoSpin( &egm ); DisplaySymbols( &egm ); return; } GtkWidget *SetupWindow(gchar *data, const gchar *filename) { // window setup code removed for brevity return(window); } int main (int argc, char *argv[]) { GtkWidget *btnSpin, *btnExit; float spinDelay = 2.0; Init(); gtk_init (&argc, &argv); window = SetupWindow("Tournament", "images/Midway_Madness_Shell.jpg"); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL); frame = gtk_fixed_new(); gtk_container_add(GTK_CONTAINER(window), frame); btnSpin = gtk_button_new_with_label("Spin"); gtk_widget_set_size_request(btnSpin, 70, 40); gtk_fixed_put(GTK_FIXED(frame), btnSpin, 720, 540); g_signal_connect(G_OBJECT( btnSpin ), "clicked", G_CALLBACK(btnSpin_clicked), NULL ); btnExit = gtk_button_new_with_label("Exit"); gtk_widget_set_size_request(btnExit, 70, 40); gtk_fixed_put(GTK_FIXED(frame), btnExit, 595, 540); g_signal_connect(G_OBJECT( btnExit ), "clicked", G_CALLBACK(btnExit_clicked), NULL ); DoSpin( &egm ); DisplaySymbols( &egm ); gtk_widget_show_all(window); gtk_main (); return( 0 ); } 

我非常感谢有关如何解决此问题的详细解释以及一些示例代码,因为我很难理解如何应用我从GTK2文档中读取的内容,这似乎只是提供了定义对象和函数调用。 如果需要一个非常彻底的回应,可以提供一个英俊的赏金。

如果拥有所有代码是有用的 , 我在这里提供了它。

编辑:内存泄漏以两种方式修复。

  1. GtkFixed建议重新绘制图像之前,销毁并重新创建GtkFixed容器。
  2. 使用指向GtkWidget的二维指针数组来保存指向每个图像的指针。 当重新绘制图像时,二维数组中的小部件指针首先被破坏,如下所示:

    int ReleaseImages(void){u_int8_t y,x;

     /* release images */ for( y = 0; y < 3; y++ ) { for( x = 0; x < 5; x++ ) { gtk_widget_destroy( ptrImages[y][x] ); } } return( 0 ); 

    }

    现在释放图像资源并重新绘制新图像。

从GtkFixed的文档 :

对于大多数应用程序,您不应该使用此容器! 它使您不必了解其他GTK +容器,但它会导致应用程序损坏。 使用GtkFixed,以下内容将导致截断文本,重叠小部件和其他显示错误…

我想强调上面引用的重叠小部件 。 随着应用程序继续运行,您将继续向GtkFixed容器添加越来越多的图像。 由于您永远不会从容器中删除图像,因此即使您无法再看到它们,它们也会继续需要内存。

不要在这方面说得太精细,但你无法看到旧图像的原因是你已经用新图像覆盖了它们。 就GtkFixed小部件而言,自应用程序启动以来添加的每个图像仍然在那里。

要解决此问题,您需要删除旧图像。 有很多方法可以做到这一点。 最简单的可能是销毁整个容器,但由于您还将按钮放入该容器中,因此存在一些复杂性。

更好的解决方案可能是遵循上面引用的建议,不要使用GtkFixed – 或者至少将应用程序分层,以便GtkFixed仅用于图像(您可以将按钮放在GtkFixed之外)。 但是如上所述,这可能需要您了解其他GTK +容器(除非您只使用第二个 GtkFixed容器来保存图像,而第一个GtkFixed容器同时容纳按钮和第二个容器)。