这是my last question regarding GTK2 dealing with resource usage.
应用程序正确地显示图像,但是现在每次从磁盘加载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
文档中读到的内容,该文档似乎只提供了对象和函数调用的定义。如果需要非常彻底的回应,可以提供一笔可观的赏金。如果拥有所有的代码是有用的,I've provided it here.
编辑:内存泄漏是通过两种方式修复的。
在按照nobar.的建议重新绘制图像之前,销毁并重新创建
GtkFixed
容器使用指向
GtkWidget
的指针的二维数组,在绘制每个图像时保留指向它们的指针。当需要重新绘制图像时,二维数组中的小部件指针首先会被销毁,如下所示:int ReleaseImages(无效)
{
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 );
}
现在图像资源被释放,新的图像可以重新绘制。
最佳答案
从documentation of GtkFixed开始:
对于大多数应用程序,不应使用此容器!它让你
从不得不了解其他GTK+容器,但它的结果
在破碎的应用程序中。在GtkFixed中,以下内容将
导致文本截断、小部件重叠和其他显示错误。。。
我想强调以上引用中重叠的小部件。随着应用程序继续运行,您将继续向GtkFixed容器添加越来越多的图像。由于您从未从容器中移除图像,因此即使您再也看不到它们,它们仍然需要内存。
不要把这一点说得太细,但你看不到旧图像的原因是你用新图像掩盖了它们。就GtkFixed小部件而言,自应用程序启动以来添加的每个图像仍在其中。
要解决此问题,需要删除旧图像。有很多方法可以做到这一点。最简单的方法可能是销毁整个容器,但也有一些复杂的问题,因为您还将按钮放入该容器中。
更好的解决方案可能是遵循上面的建议,不要使用GtkFixed——或者至少对应用程序分层,这样GtkFixed只用于图像(您可以将按钮放在GtkFixed之外)。但如前所述,这可能需要您了解其他GTK+容器(除非您只是使用第二个GtkFixed容器保存图像,而第一个GtkFixed容器同时保存按钮和第二个容器)。