1

这是我关于 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 <gdk/gdkx.h>
#include <gtk/gtk.h>

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. 按照nobarGtkFixed的建议,在重绘图像之前销毁并重新创建容器。
  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 );
    

    }

    现在图片资源已经发布,可以重新绘制新的图片了。

4

1 回答 1

3

GtkFixed 的文档中

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

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

对此不要说得太细,但是您看不到旧图像的原因是您已经用新图像覆盖了它们。就 GtkFixed 小部件而言,自应用程序开始以来您添加的每个图像都仍然存在。

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

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

于 2012-08-01T06:11:06.350 回答