使用多个图像GTK2应用程序内存泄漏 [英] GTK2 application memory leak using multiple images

查看:584
本文介绍了使用多个图像GTK2应用程序内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个跟进我就GTK2处理资源使用最后一个问题。

应用程序能否正常显示图像,但现在看来 GtkImages 每次从磁盘加载并放在了绝对定位的固定框架,将泄漏一些内存

我使用的是被称为每隔几秒钟以下几个基本的方法来加载和显示不同的图像。

  INT DisplaySymbols(*的GameInfo米)
{
    //为简洁起见删除变量声明
    //错误检查需要添加
    * GtkWidget的形象;    POS_Y = 150;
    为(γ= 0; Y 3;; Y +)
    {
    POS_X = 187;
        为(X = 0; X小于5; X +)
        {
            图像= gtk_image_new_from_file(文件名);
            gtk_fixed_put(GTK_FIXED(帧),图像,POS_X,POS_Y);
        POS_X + =符号[I] .pixel_width;
        }
    POS_Y + =符号[I] .pixel_height;
    }
    gtk_widget_show_all(窗口);
    返回(0);
}

我读过关于资源使用 GTK + 文档的部分,我只是不能完全弄清楚如何使用 API 调用prevent内存泄漏。

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


  • 我应该创造一些图像保持部件的固定框架更轻松地管理放在帧图像?

  • 什么是我的code做什么或不做是导致内存被泄露?我可能不会释放 GtkImage 小部件?

  • 这似乎有点低效从磁盘每次我需要使用它们时加载图像。我怎么可以读取到内存,然后在框架需要?显示它们

部分源$ C ​​$ c是如下:

  //使用编译我:GCC -o泄漏leak.c $(pkg配置--cflags --libs GTK + -2.0 gmodule-2.0)//包括简洁,删除文件
/ * GTK * /
#包括LT&; GDK / gdkx.h>
#包括LT&; GTK / gtk.h>typedef结构
{
    unsigned int类型pixel_width,pixel_height;
    gchar文件名[20];
} symbol_t;静态symbol_t符号[] =
{
    / *只显示2八 - 简洁* /
    {118,107,图像/ LO.jpg},
    {118,107,图像/ L1.jpg}
};typedef结构
{
    炭SpinResult [3] [5]; //图像索引指向为符号结构
}的GameInfo;临时股东大会的GameInfo;* GtkWidget的框架; / *窗口小部件的绝对positionining * /
* GtkWidget的窗口;/ **** ****原型/
    //删除简洁
/ ****** ///初始化随机数发生器
INT初始化(无效)
{
    //创建随机数 - 简洁
}//确定自旋结果,并存储到egm.SpinResult阵列
INT DoSpin(*的GameInfo EGM)
{
    //生成索引矩阵为符号结构
    //所以我们知道什么是符号在画面中显示
}诠释DisplaySymbols(*的GameInfo EGM)
{
    //变量声明中删除 - 简洁
    * GtkWidget的形象;    POS_Y = 150;
    为(γ= 0; Y 3;; Y +)
    {
        POS_X = 187;
        为(X = 0; X小于5; X +)
        {
            图像= gtk_image_new_from_file(符号[I] .fileName);
            gtk_fixed_put(GTK_FIXED(帧),图像,POS_X,POS_Y);
            POS_X + =符号[I] .pixel_width;
        }
        POS_Y + =符号[I] .pixel_height;
    }
    gtk_widget_show_all(窗口);
    返回(0);
}无效btnSpin_clicked(GtkWidget的*键,gpointer数据)
{
    DoSpin(安培; EGM);
    DisplaySymbols(安培; EGM);
    返回;
}GtkWidget的* SetupWindow(gchar *数据常量gchar *文件名)
{
    //窗口设置code为简洁起见删除
    返回(窗口);
}INT主(INT ARGC,CHAR *的argv [])
{
    GtkWidget的* btnSpin,* btnExit;
    浮spinDelay = 2.0;    在里面();
    gtk_init(安培; ARGC,&安培; argv的);
    窗口= SetupWindow(对抗赛,图像/ Midway_Madness_Shell.jpg);
    g_signal_connect(G_OBJECT(窗口),消灭,G_CALLBACK(破坏),NULL);    帧= gtk_fixed_new();
    gtk_container_add(GTK_CONTAINER(窗口),帧);    btnSpin = gtk_button_new_with_label(旋转);
    gtk_widget_set_size_request(btnSpin,70,40);
    gtk_fixed_put(GTK_FIXED(帧),btnSpin,720,540);
    g_signal_connect(G_OBJECT(btnSpin),点击,G_CALLBACK(btnSpin_clicked),NULL);    btnExit = gtk_button_new_with_label(退出);
    gtk_widget_set_size_request(btnExit,70,40);
    gtk_fixed_put(GTK_FIXED(帧),btnExit,595,540);
    g_signal_connect(G_OBJECT(btnExit),点击,G_CALLBACK(btnExit_clicked),NULL);    DoSpin(安培; EGM);
    DisplaySymbols(安培; EGM);    gtk_widget_show_all(窗口);
    进入主循环();
    返回(0);
}

我将是如何解决这个问题的详细说明,以及因为我有一个很难理解如何运用我所从<$ C $读一些例如code非常感谢C> GTK2 这似乎只是提供对象和函数调用的定义文件。可以根据需要进行非常彻底的响应提供一个英俊的赏金。

如果这是非常有用的所有$ C $的C 我提供了它这里

编辑:内存泄漏是固定在两个方面


  1. 破坏和的 GtkFixed 容器=htt​​p://stackoverflow.com/users/86967/nobar > nobar。

  2. 使用指针的二维阵列,以的GtkWidget 来容纳指针到每一个图像,因为它们是绘制。当它的时间来重新绘制二维数组在widget指针首先破坏了这样的图片:

    INT ReleaseImages(无效)
    {
        u_int8_t Y,X;

      / *释放图像* /
    为(γ= 0; Y 3;; Y +)
    {
        为(X = 0; X小于5; X +)
        {
            gtk_widget_destroy(ptrImages [Y] [X]);
        }
    }
    返回(0);

    }

    现在的图像资源被释放,新的图像可以被重新绘制。



解决方案

文档GtkFixed :


  

对于大多数应用程序,你不应该使用这个容器!它使你
  不必了解其他GTK +容器,但它的结果
  在破碎的应用。随着GtkFixed,下面的事情会
  结果截断文字,重叠的窗口小部件,以及其他显示错误...


从以上报价

我想强调的重叠的小部件的。随着应用程序继续运行,你继续越来越多的图像添加到GtkFixed容器。因为你永远不会从容器中删除图像,它们仍然需要内存,即使你再也看不到他们。

不要把这个太细了点,但你不能看到老照片的原因是,你已经把它们与新的图像。至于GtkFixed部件而言,每次因为应用程序开始你已经添加图像仍然在那里。

要解决这个问题,您需要删除旧的图像。有很多方法,你可以做到这一点。最简单的可能是破坏整个容器,但也有一些并发症,由于还放按钮到该容器中。

更好的解决方案可能是按照从上述报价的建议,不要使用GtkFixed - 或者至少层应用程序,以便GtkFixed仅用于图像(你可以放置GtkFixed外的按钮) 。但如前所述,这可能需要您了解其他GTK +容器(除非你只需要使用第二的GtkFixed容器,而第一GtkFixed容器包含两个按钮和第二个容器来保存图像)。

This is a follow up to my last question regarding GTK2 dealing with resource usage.

The application is properly displaying images, however it now appears to be leaking some memory every time GtkImages are loaded from disk and placed onto a fixed frame for absolute positioning.

I'm using the following basic method called every few seconds to load and display different sets of images.

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 );
} 

I've read parts of the GTK+ documentation regarding resource usage and I just can't quite figure out how to use the API calls to prevent memory leaks.

Some thoughts and/or questions I have:

  • Should I create some image holding widgets in the fixed frame to more easily manage the images placed in the frame?
  • What is my code doing or not doing that is causing memory to be leaked? I'm likely not releasing the GtkImage widgets?
  • It seems a bit inefficient to load the images from disk every time I need to use them. How can I read them into memory and then display them in the frame as needed?

Partial source code is as follows:

//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 );
}

I would be very grateful for a detailed explanation of how to resolve this problem as well as some example code as I'm having a hard time understanding how to apply what I've read from the GTK2 documentation which appears to just provide the definition of objects and the function calls. A handsome bounty can be provided if needed for a very thorough response.

If it is useful to have all of the code, I've provided it here.

EDIT: The memory leak was fixed in two ways.

  1. destroy and re-create the GtkFixed container before redrawing the images as suggested by nobar.
  2. use a two-dimensional array of pointers to GtkWidget to hold the pointers to each image as they are drawn. When it's time to redraw the images the widget pointers in the two-dimensional array are first destroyed like this:

    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 );
    

    }

    Now the image resources are released and new images can be redrawn.

解决方案

From the documentation of GtkFixed:

For most applications, you should not use this container! It keeps you from having to learn about the other GTK+ containers, but it results in broken applications. With GtkFixed, the following things will result in truncated text, overlapping widgets, and other display bugs...

I would like to emphasize overlapping widgets from the above quote. As your application continues to run, you continue to add more and more images to the GtkFixed container. Since you never remove images from the container, they continue to require memory even though you can no longer see them.

Not to put too fine a point on this, but the reason you can't see the old images is that you have covered them up with new images. As far as the GtkFixed widget is concerned, every image you have added since the application began is still in there.

To fix this, you need to remove the old images. There are many ways that you could do this. The simplest might be to destroy the entire container, but there are some complications with that since you also put the buttons into that container.

The better solution is probably to follow the advice from the above quote and don't use GtkFixed -- or at least layer your application so that GtkFixed is only used for the images (you could place the buttons outside of the GtkFixed). But as noted, this might require you to learn about the other GTK+ containers (unless you just use a second GtkFixed container to hold the images while the first GtkFixed container holds both the buttons and the second container).

这篇关于使用多个图像GTK2应用程序内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆